码迷,mamicode.com
首页 > Web开发 > 详细

实时捕捉以太网原始数据包(PacketRawEthernetMonitor)----Kithara RTS工程源代码解析

时间:2014-07-19 09:14:26      阅读:476      评论:0      收藏:0      [点我收藏+]

标签:des   style   blog   color   使用   strong   

本文以windows实时拓展Kithara RTS安装目录下的smp文件夹内的PacketRawEthernetMonitor工程源码为例,
该源码实现了一个简单的网络监视程序,可以实时监测网卡接收的原始数据。
该工程主要使用了Kernel,Packet模块,有三个函数组成:主函数runSample,回调函数_callBack,线程_recvThread,_callBack和_recvThread之间存在着同步关系,线程_recvThread运行时会堵塞等待事件,回调函数设置该事件后线程才能继续运行。
程序运行过程如下:
1、进入主函数,打开kithara RTS,建立共享内存区域,枚举以太网卡并选择一个需要的网卡,建立一个管道,用于回调函数与接收线程之间的数据交互
2、创建一事件(event),用于回调函数_callBack和线程_recvThread之间的同步。
3、创建线程_recvThread,该线程开始即处于阻塞状态,等待事件被设置。事件被设置后,本线程将继续运行,从管道中取出数据并在屏幕上显示。
4、创建回调函数_callBack,在网卡接收到数据时将触发该回调函数运行,该函数的作用是将接收的数据包存入管道中,然后设置事件以触发_recvThread继续运行。
5、创建一个标志位,如果置为false,recvThread线程进入while循环,等待事件触发其读取管道中的数据并显示;如果置为ture,线程函数不再读取数据,
6、使用函数KS_installPacketHandler将网卡数据接收事件和回调函数_callBack关联,然后设置事件,此时程序进入正式的工作状态。
7、最后退出程序,首先停止数据读取,取消回调函数关联,然后进行资源回收处理工作。

// Used Modules:     Kernel Module, Packet Module//使用到的模块
//                                                                                                 
// Descript.:        Sample application showing how to implement a raw
//                   ethernet monitor application  //形成一个以太网监视应用程序
// Purpose:
//
// This example shows how to program a raw ethernet monitoring application.
//该例子展示了如何编制一个基本的以太网监视程序
// First, the program opens the driver and the Ethernet adapter.//首先,打开驱动及网卡适配器
// We install the receiver callback.安装接收器回调函数
// A receive thread is displaying the mac header, which is submitted by a pipe. 接收线程通过管道显示mac头
// Finally we release all used resources and close the driver.最后清理资源
//
// Attention! It is nessary that there is no switch between our adapter and the adapter we want to trace!不能对适配器进行切换
// Otherwise, only broadcast messages will be monitored!  否则只能监视反馈回来的信息
//
// ATTENTION! Network cards can only be used here, when the driver of the card has been switched to Kithara!
// It is not possible to use the original driver for real-time! Please refer to the manual, chapter 16
// "Packet Module" for further instructions on switching the driver to Kithara!


#include "..\_KitharaSmp\_KitharaSmp.h"


const char* pCustomerNumber = "DEMO";


//--------------------------------------------------------------------------------------------------------------
// This is a user defined argument structure to the callback routine.用户定义回调函数结构体
// You are free to define your own arguments in any record/class.
//--------------------------------------------------------------------------------------------------------------

//------ CallBackData ------
struct CallBackData {   //回调数据的结构体,
  Handle hAdapter_;     //适配器句柄
  Handle hCallBack_;    //回调函数句柄
  Handle hEvent_;       //事件句柄
  Handle hPipe_;        //管道句柄
  bool finished_;       //标志位
};

//当接收到数据包时,将数据包地址存在管道中
//--------------------------------------------------------------------------------------------------------------
// These are user defined callback routines. They are called every time a packet is received.一下定义回调函数,当有数据包接收到的时候调用
// We put the data in a pipe and set the receive event. 将数据放入管道中,设置接收数据的事件
//--------------------------------------------------------------------------------------------------------------

//------ _callBack ------回调函数的定义
static Error __stdcall _callBack(void* pArgs, void* pContext) {
  CallBackData* pData = (CallBackData*)pArgs;
  PacketUserContext* pUserContext = (PacketUserContext*)pContext;

  Error ksError;

  ksError = KS_putPipe(                                 // 将数据包地址放入管道中
              pData->hPipe_,                            // Pipe handle,管道对应的句柄
              &pUserContext->pPacketApp,                // Address of pointer to packet,待存入管道中的数据内存地址,这里是接收的数据包地址
              1,                                        // Item count,数量
              NULL,                                     // Number of bytes transmitted ,Number of bytes transmitted so far.
              0);                                       // Flags, here none
  if (ksError != KS_OK)
    return ksError;

  ksError = KS_setEvent(                                // 设置事件,触发线程继续运行
              pData->hEvent_);                          // Event handle事件句柄
  if (ksError != KS_OK)
    return ksError;

  return KS_OK;
}


//--------------------------------------------------------------------------------------------------------------
// This is the user defined thread function. It contains a loop in which the thread waits for the event
// signalization whenever a packet is received.线程,等待事件信号,然后将管道中的数据取出并显示数据包头,最后释放数据包的内存对象
// After displaying the packet header, the packet must be released with KS_releasePacket.
//--------------------------------------------------------------------------------------------------------------

Error __stdcall _recvThread(void* pArgs) {//也是一个回调函数,接收数据的线程

  Error ksError = KS_OK;
  CallBackData* pData = (CallBackData*)pArgs;

  while (!pData->finished_) {             //


    //----------------------------------------------------------------------------------------------------------
    // Wait for the event to be set.
    //----------------------------------------------------------------------------------------------------------

    ksError = KS_waitForEvent(                          // 等待接收数据
                pData->hEvent_,                         // Event handle在回调函数中定义的事件
                0,                                      // Flags
                0);                                     // Time-out, in 100-ns-units
    if (ksError != KS_OK)
      return ksError;

    KSMACHeader* pHeader;
    while (KS_getPipe(pData->hPipe_, &pHeader, 1, NULL, 0) == KS_OK) {
      outputTxt(" ", true);//读出管道中的数据,并显示出来
      for (int i = 0; i < 3; ++i)
        outputHex(KS_ntohs(*(ushort*)&pHeader->source[i * 2]), "", "", false);

      outputTxt(" -> ", false);

      for (int i = 0; i < 3; ++i)
        outputHex(KS_ntohs(*(ushort*)&pHeader->destination[i * 2]),
                  "", "", false);
      outputHex(KS_ntohs(pHeader->typeOrLength), " typeOrLength: ", "", false);

      //--------------------------------------------------------------------------------------------------------
      // Finally we release the packet.最后清空数据包
      //--------------------------------------------------------------------------------------------------------

      ksError = KS_releasePacket(//释放数据包
                  pData->hAdapter_,                     // Adapter handle,网卡句柄
                  pHeader,                              // Pointer to packet,指向数据包的指针
                  KSF_RAW_ETHERNET_PACKET);             // Flags,标志
      if (ksError != KS_OK)
        return ksError;
    }
  }

  outputTxt("Thread has been finished.");
  return ksError;
}


//--------------------------------------------------------------------------------------------------------------
// This is the main program 主函数
//--------------------------------------------------------------------------------------------------------------

void runSample() {
  outputTxt("***** Kithara example program ‘PacketRawEthernetMonitor‘ *****");

  Error ksError;
///////////////////////////////////////////////////////////////////////
//////1.程序初始化
///////////////////////////////////////////////////////////////////////
//------------------------------------------------------------------------------------------------------------ // Opening the driver is always the first step! After that, we can use other functions. If the opening fails, // no other function can be called. // // This function takes your customer number with Kithara (or "DEMO" or "BETA" if applicable) as a parameter. //------------------------------------------------------------------------------------------------------------ ksError = KS_openDriver(//第一步,打开驱动 pCustomerNumber); // Customer number 已定义const char* pCustomerNumber = "DEMO"; if (ksError) { outputErr(ksError, "KS_openDriver", "Maybe incorrect customer number?"); return; } //------------------------------------------------------------------------------------------------------------ // Allocation of Sharedmem分配共享内存 //------------------------------------------------------------------------------------------------------------ CallBackData* pAppPtr; //结构体指针 CallBackData* pSysPtr; ksError = KS_createSharedMem(//创建共享内存 (void**)&pAppPtr, // App Pointer (void**)&pSysPtr, // Sys Pointer "MyPacketRawEthernetMonitorMemory", // Name sizeof(CallBackData), // Size大小为定义的结构体大小 0); // Flags if (ksError != KS_OK) { outputErr(ksError, "KS_createSharedMem", "Failed to allocate shared memory"); KS_closeDriver(); return; } //------------------------------------------------------------------------------------------------------------ // First, the names of all network adapters are queried and displayed首先,查询并显示所有网络适配器 //------------------------------------------------------------------------------------------------------------ char pDeviceName[256];//定义一个大小为256的char型数组 outputTxt(" "); outputTxt("Following network adapters found:"); for (int i = 0; ; ++i) { //---------------------------------------------------------------------------------------------------------- // The following function can be used to query the names of all network adapters assigned to the Kithara // Driver. The number ‘i‘ runs beginning from zero. //枚举可用的网卡适配器,选择一个使用 // ATTENTION! Network cards can only be used here, when the driver of the card has been switched to Kithara! // It is not possible to use the original driver for real-time! Please refer to the manual, chapter 16 // "Packet Module" for further instructions on switching the driver to Kithara! //---------------------------------------------------------------------------------------------------------- ksError = KS_enumDevices(//枚举设备的函数 "NET", // Searches for network devices,专门寻找有关网络的设备 i, // Count, starting with zero计数 pDeviceName, // Buffer for device name 设备名称 0); // Flags if (ksError != KS_OK) { if (KSERROR_CODE(ksError) != KSERROR_DEVICE_NOT_FOUND) outputErr(ksError, "KS_enumDevices", "Unable to query network device name!"); if (KSERROR_CODE(ksError) == KSERROR_DEVICE_NOT_FOUND && !i) { outputTxt("No devices found"); outputTxt(" "); outputTxt("Did you switch the network card driver to Kithara?"); outputTxt("Please refer to the manual, chapter 16 \"Packet Module\""); outputTxt("for further instructions!"); KS_closeDriver(); return; } break; } outputDec(i, "", ": ", false); outputTxt(pDeviceName); } outputTxt(" "); //------------------------------------------------------------------------------------------------------------ // Please enter the index of the adapter, which should be opened上一个函数时枚举,现在选择,index不同,选择好,打开网络适配器 //------------------------------------------------------------------------------------------------------------ int deviceIndex = inputDec("Device number: ", ""); ksError = KS_enumDevices( "NET", // Searches for network devices deviceIndex, // Index of device pDeviceName, // Buffer for device name 0); // Flags if (ksError != KS_OK) { outputErr(ksError, "KS_enumDevices", "Unable to query network device name!"); KS_closeDriver(); return; } outputTxt("Selected device: ", false); outputTxt(pDeviceName); //------------------------------------------------------------------------------------------------------------ // Then we open the network adapter. // // Please enter a part of the hardware ID of your network controller. // e.g. // Intel: "VEN_8086" // Realtek: "PCI\\VEN_10EC&DEV_8139" or "DEV_8139" //------------------------------------------------------------------------------------------------------------ //选择好之后,打开选择好的网卡适配器 ksError = KS_openAdapter( &pAppPtr->hAdapter_, // Adapter handle pDeviceName, // Device name of the adapter 100, // Receive Pool Length 0, // Send Pool Length KSF_RAW_ETHERNET_PACKET | KSF_ACCEPT_ALL); // Flags if (ksError != KS_OK) { outputErr(ksError, "KS_openAdapter", "Failed to open adapter"); KS_closeDriver(); return; } //------------------------------------------------------------------------------------------------------------ // Here we set a mac multicast address, cause we want to display all packets going to this address.设置一个mac地址,来显示经过此地址的数据包 // It is necessary that there is no network switch between our adapter and the adapter we want to trace //注意:适配器跟要追溯的适配器不能切换 //------------------------------------------------------------------------------------------------------------ byte multi[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; ksError = KS_execAdapterCommand(//对网络适配器进行操作 pAppPtr->hAdapter_, // Adapter handle KS_PACKET_SET_MAC_MULTICAST, // Command, Adds a MAC multicast address to the reception filter. multi, // Data 数据包存在这里面啦 0); // Flags if (ksError != KS_OK) { outputErr(ksError, "KS_execAdapterCommand", "Failed to execute command"); KS_closeDriver(); return; } //------------------------------------------------------------------------------------------------------------ // For data transfer between the async callbacks and the receive thread we use a pipe. // 用一个管道来进行异步回调与接收线程之间数据传输 //------------------------------------------------------------------------------------------------------------ ksError = KS_createPipe( //创建管道 &pAppPtr->hPipe_, // Pipe Handle "MyPacketRawEthernetMonitorPipe", // Name管道名称 sizeof(void*), // Item size, here pointer size 100, // Item count NULL, // Object to signal 0); // Flags if (ksError != KS_OK) { outputErr(ksError, "KS_createPipe", "Unable to create pipe!"); KS_closeDriver(); return; } //------------------------------------------------------------------------------------------------------------ // Create an event object, which will be signalled when a packet arrives. 创建一事件,当有数据包到达时,有相应信号 //每当有数据接收到时 有相应信号 //------------------------------------------------------------------------------------------------------------ ksError = KS_createEvent( &pAppPtr->hEvent_, // Event handle "MyPacketRawEthernetMonitorEvent", // Name of event 0); // Flags, here 0 if (ksError != KS_OK) { outputErr(ksError, "KS_createEvent", "Unable to create finish event!"); KS_closeDriver(); return; } //------------------------------------------------------------------------------------------------------------ // Now create the thread.创建线程 //------------------------------------------------------------------------------------------------------------ ksError = KS_createThread( //调用线程回调函数,当有信号(event产生),说明有数据,将数据从管道中读出 _recvThread, // Thread function,调用回调函数,开始等待信号,有event信号,开始读出数据 pAppPtr, // Parameter to the thread NULL); // Address of thread handle, // not needed here if (ksError != KS_OK) { outputErr(ksError, "KS_createThread", "Unable to create the thread!"); KS_closeDriver(); return; } //------------------------------------------------------------------------------------------------------------ // For signalization we use a callback 回调函数 //------------------------------------------------------------------------------------------------------------ ksError = KS_createCallBack( &pAppPtr->hCallBack_, // Address of callback handle 句柄地址 _callBack, // Callback Routine 接收数据 将接收的数据放入管道中,并设置event,触发waitforevent,读出这里写入的数据 pSysPtr, // Reference parameter to the callback KSF_DIRECT_EXEC, // Flags, here kernel level in realtime context 0); // Priority if (ksError != KS_OK) { outputErr(ksError, "KS_createCallBack", "Failed to create callback"); KS_closeDriver(); return; } //------------------------------------------------------------------------------------------------------------ // Finally we start the packet receiver with KS_recvPackets.程序中没有KS_recvPackets的,源码注释错误。 // The signalization object must be a callback create with DIRECT_EXEC.
// KS_installPacketHandler函数的作用是为网卡的某个事件(这里是收到数据包时触发的事件KS_PACKET_RECV)关联一个回调函数(pAppPrt->hCallBack),在事件触发时该回调函数将会被执行 //------------------------------------------------------------------------------------------------------------
pAppPtr->finished_ = false; // false表示线程中开始接收数据 ksError = KS_installPacketHandler( // 安装数据包处理函数 pAppPtr->hAdapter_, // Adapter handle KS_PACKET_RECV, // Event code 安装好用该函数进行数据包的接收,开始接收数据包 pAppPtr->hCallBack_, // Callback handle,调用回调函数,将采集到的数据包的地址放入管道中 KSF_RAW_ETHERNET_PACKET); // Flags Enables the raw ethernet packet mode for the handle,处理的是原始数据包 if (ksError != KS_OK) { outputErr(ksError, "KS_installPacketHandler", "Failed to install handler"); KS_closeDriver(); return; } inputTxt("Press <enter> to stop... "); outputTxt(" "); /////以下为程序退出部分 //------------------------------------------------------------------------------------------------------------ // Set the event, so the thread can be finished. Before that, we set the variable ‘finished_‘ to true, so the // thread knows it should terminate. //------------------------------------------------------------------------------------------------------------ pAppPtr->finished_ = true; //首先线程中接收到数据显示,然后线程关闭,以下是停止接收数据 //------------------------------------------------------------------------------------------------------------ // To stop the receiver, we set the Callback handle to NULL. 停止接收数据 //------------------------------------------------------------------------------------------------------------ ksError = KS_installPacketHandler( pAppPtr->hAdapter_, // Adapter handle KS_PACKET_RECV, // Event code NULL, // Callback handle句柄为null,停止接收数据 KSF_RAW_ETHERNET_PACKET); // Flags if (ksError != KS_OK) { outputErr(ksError, "KS_installPacketHandler", "Failed to uninstall handler"); KS_closeDriver(); return; } ksError = KS_setEvent(pAppPtr->hEvent_); if (ksError != KS_OK) outputErr(ksError, "KS_setEvent", "Setting event failed!"); waitTime(500 * ms); //------------------------------------------------------------------------------------------------------------ // Display the adapter state 以下是显示适配器信息 //------------------------------------------------------------------------------------------------------------ KSAdapterState state; state.structSize = sizeof(KSAdapterState); ksError = KS_getAdapterState( //获取适配器信息函数 pAppPtr->hAdapter_, // Adapter handle &state, // Pointer to Buffer 0); // Flags if (ksError != KS_OK) outputErr(ksError, "KS_getAdapterState", "Querying the adapter state failed!"); else { outputTxt(" "); outputDec(state.numPacketsSendOk, "Number of packets sent successfully: ", ""); outputDec(state.numPacketsSendError, "Number of packets failed to send: ", ""); outputDec(state.numPacketsSendARPTimeout, "Number of packets failed because of ARP timeout: ", ""); outputDec(state.numPacketsWaitingForARP, "Number of packets waiting for ARP: ", ""); outputDec(state.numPacketsRecvOk, "Number of packets received successfully: ", ""); outputDec(state.numPacketsRecvError, "Number of packets failed to receive: ", ""); outputTxt(" "); } //------------------------------------------------------------------------------------------------------------ // Close the Adapter. //------------------------------------------------------------------------------------------------------------ ksError = KS_closeAdapter( //关闭适配器 pAppPtr->hAdapter_); // Adapter handle if (ksError != KS_OK) outputErr(ksError, "KS_closeAdapter", "Unable to close Adapter!"); //------------------------------------------------------------------------------------------------------------ // Remove callbacks. //------------------------------------------------------------------------------------------------------------ ksError = KS_removeCallBack( pAppPtr->hCallBack_); // Callback handle if (ksError != KS_OK) outputErr(ksError, "KS_removeCallBack", "Unable to remove the callback!"); //------------------------------------------------------------------------------------------------------------ // Close the event object //------------------------------------------------------------------------------------------------------------ ksError = KS_closeEvent( pAppPtr->hEvent_); // Event handle if (ksError != KS_OK) outputErr(ksError, "KS_closeEvent", "Unable to close event!"); //------------------------------------------------------------------------------------------------------------ // Remove the data pipe //------------------------------------------------------------------------------------------------------------ ksError = KS_removePipe( pAppPtr->hPipe_); // Pipe handle if (ksError != KS_OK) outputErr(ksError, "KS_removePipe", "Unable to remove the pipe!"); //------------------------------------------------------------------------------------------------------------ // Remove the shared memory //------------------------------------------------------------------------------------------------------------ ksError = KS_freeSharedMem( pAppPtr); // Application pointer if (ksError != KS_OK) outputErr(ksError, "KS_freeSharedMem", "Unable to remove shared memory!"); //------------------------------------------------------------------------------------------------------------ // At last we have to close the driver to free any allocated resources. //------------------------------------------------------------------------------------------------------------ ksError = KS_closeDriver(); if (ksError != KS_OK) outputErr(ksError, "KS_closeDriver", "Unable to close the driver!"); waitTime(500 * ms); outputTxt("End of program ‘PacketRawEthernetMonitor‘."); outputTxt("Press <enter> to close."); }

实时捕捉以太网原始数据包(PacketRawEthernetMonitor)----Kithara RTS工程源代码解析,布布扣,bubuko.com

实时捕捉以太网原始数据包(PacketRawEthernetMonitor)----Kithara RTS工程源代码解析

标签:des   style   blog   color   使用   strong   

原文地址:http://www.cnblogs.com/sunvhao/p/3854379.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!