I write a program to capture the packets using Library "Winpcap". ( How to complie WinPcap with VS2010? Please see this link: http://www.rhyous.com/2011/11/12/how-to-compile-winpcap-with-visual-studio-2010/)
I want to capture the packet(using pcap_loop())
and at the same time I process the packet in the same function void D
. The code int x = 1;
in function void D
is only an easy example which represents some functions that can process the packet. The thread t
calls void D
. The thread tt
calls the function startCap()
which captures the packet.
I want to emphasize my question: I debug the program and it stops at the position of pcap_loop()
in thread tt
until pcap_loop()
finishes. I set the parameter of pcap_loop()
to make it to run without end because I need continious capture of packet. The result is that the program will not go to the next step int x = 1;
. I want to run int x = 1;
as thread tt
runs. In a word, I wish that the both threads t
and tt
run at the same time. But the program runs only on thread tt
without jumping out and run on thread t
.
PS 1: int x = 1;
keeps staying better in void D
.
PS 2: There's no erros in compiling and debuging. But the program falls into the function pcap_loop
which is in the thread tt
.
Did I make my question clear?
The whole code:
Data.h
#ifndef DATA_H
#define DATA_H
#include <pcap/pcap.h>
#include <vector>
using namespace std;
struct PcapDevice
{
string name;
string description;
};
class Data
{
public:
Data();
~Data();
bool findDevices(vector<PcapDevice> &deviceList );
bool openDevices(const char * device);
void processPacket();
void startCap();
private:
pcap_t* inData;
char errbuf[256];
bool isCapturing;
pcap_if_t * m_pDevs;
};
#endif // DATA_H
Data.cpp
#include "Data.h"
#include <iostream>
// define pcap callback
void capture_callback_handler(unsigned char *userData, const struct pcap_pkthdr* pkthdr, const unsigned char * packet)
{
((Data*) userData)->processPacket();
}
Data::Data()
{
memset(errbuf,0,PCAP_ERRBUF_SIZE);
isCapturing = false;
inData = NULL;
m_pDevs = NULL;
}
Data::~Data()
{
}
// process the packet
void Data::processPacket()
{
return ;
}
// find local adapter
bool Data::findDevices(vector<PcapDevice> &deviceList )
{
m_pDevs = NULL;
int res = pcap_findalldevs(&m_pDevs, errbuf);
if(0 == res)
{
pcap_if_t * pIter = m_pDevs;
while(pIter != NULL)
{
PcapDevice device;
device.description = pIter->description;
device.name = pIter->name;
deviceList.push_back(device);
pIter = pIter->next;
}
return true;
}
else
{
printf("PCAP: no devices found\n");
}
return false;
}
// open the adapter
bool Data::openDevices(const char *device)
{
if ( (inData = pcap_open_live(device, 8192, 1, 512, errbuf)) == NULL)
{
return false;
}
return true;
}
// start the process of capturing the packet
void Data::startCap()
{
if ( inData == NULL ){
fprintf(stderr, "ERROR: no source set\n" );
return;
}
// free the list of device(adapter)
pcap_freealldevs(m_pDevs);
Data* data = this;
isCapturing = true;
// capture in the loop
if ( pcap_loop(inData, -1, capture_callback_handler, (unsigned char *) data) == -1)
{
fprintf(stderr, "ERROR: %s\n", pcap_geterr(inData) );
isCapturing = false;
}
}
main.cpp
#include <WinSock2.h>
#include <Windows.h>
#include <time.h>
#include "Data.h"
#include <boost\thread\thread.hpp>
#include <boost\function.hpp>
struct parameter
{
Data* pData;
};
void D(void* pParam)
{
// init the parameter
parameter* pUserParams = (parameter*)pParam;
boost::function<void()> f;
// the capture thread will be started
f = boost::bind(&Data::startCap, pUserParams->pData);
boost::thread tt(f);
tt.join();
// I want to work on the packet at the same time, the code "int x=1" is only an easy example
// and it represents a series of functions that can process the packet. I want to run those function as the thread tt runs.
int x = 1;
}
void main()
{
Data oData;
parameter pPara ;
pPara.pData = &oData;
std::vector<PcapDevice> DevList;
oData.findDevices(DevList);
int num = DevList.size()-1;
oData.openDevices(DevList[num].name.c_str());
boost::thread t(D,(void*)&pPara);
t.join();
}
Calling tt.join()
will wait until the thread finishes (that is, startCap()
returns) before executing the next statement.
You can simply put your int x = 1;
before the join()
; however, the thread may have not have even started at that point. If you want to ensure the thread is running, or up to a certain point before processing int x = 1;
you can use a condition_variable
:
The condition_variable class is a synchronization primitive that can be used to block a thread, or multiple threads at the same time, until:
- a notification is received from another thread
void Data::startCap(std::condition_variable& cv)
{
if ( inData == NULL ){
fprintf(stderr, "ERROR: no source set\n" );
return;
}
// free the list of device(adapter)
pcap_freealldevs(m_pDevs);
Data* data = this;
isCapturing = true;
// Notify others that we are ready to begin capturing packets
cv.notify_one();
// capture in the loop
if ( pcap_loop(inData, -1, capture_callback_handler, (unsigned char *) data) == -1)
{
fprintf(stderr, "ERROR: %s\n", pcap_geterr(inData) );
isCapturing = false;
}
}
void D(void* pParam)
{
// init the parameter
parameter* pUserParams = (parameter*)pParam;
// Create conditional_variable
std::conditional_variable cv;
// Pass the conditional_variable by reference to the thread
boost::thread tt(&Data::startCap, pUserParams->pData, std::ref(cv));
// Wait until the thread notifies us it's ready:
cv.wait();
// Process packets etc.
int x = 1;
// Wait for the thread to finish
tt.join();
}
Now D()
will start the thread tt
and then wait until startCaps
has reached a certain point (where it calls notify_one()
) before we continuing doing things.