Skip to content

Commit 8b1a9a5

Browse files
authored
Refactor worker thread capture procedures as internal functions. (#1971)
* Refactor worker thread capture procedures as internal functions. * Temp removed exception handling code. * Lint
1 parent a789e12 commit 8b1a9a5

File tree

2 files changed

+134
-85
lines changed

2 files changed

+134
-85
lines changed

Pcap++/header/PcapLiveDevice.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,8 @@ namespace pcpp
103103
// Should be set to true by the Callee for the Caller
104104
std::atomic<bool> m_CaptureThreadStarted;
105105

106-
OnPacketArrivesCallback m_cbOnPacketArrives;
107-
void* m_cbOnPacketArrivesUserCookie;
108106
OnPacketArrivesStopBlocking m_cbOnPacketArrivesBlockingMode;
109107
void* m_cbOnPacketArrivesBlockingModeUserCookie;
110-
RawPacketVector* m_CapturedPackets;
111-
bool m_CaptureCallbackMode;
112108
LinkLayerType m_LinkType;
113109
bool m_UsePoll;
114110

@@ -124,11 +120,6 @@ namespace pcpp
124120
void setDeviceMacAddress();
125121
void setDefaultGateway();
126122

127-
// threads
128-
void captureThreadMain();
129-
130-
static void onPacketArrives(uint8_t* user, const struct pcap_pkthdr* pkthdr, const uint8_t* packet);
131-
static void onPacketArrivesNoCallback(uint8_t* user, const struct pcap_pkthdr* pkthdr, const uint8_t* packet);
132123
static void onPacketArrivesBlockingMode(uint8_t* user, const struct pcap_pkthdr* pkthdr, const uint8_t* packet);
133124

134125
public:

Pcap++/src/PcapLiveDevice.cpp

Lines changed: 134 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,126 @@ namespace pcpp
272272
}
273273
PCPP_LOG_DEBUG("Ended periodic statistics update procedure");
274274
}
275+
276+
struct CaptureContext
277+
{
278+
PcapLiveDevice* device = nullptr;
279+
OnPacketArrivesCallback callback;
280+
void* userCookie = nullptr;
281+
};
282+
283+
struct AccumulatorCaptureContext
284+
{
285+
PcapLiveDevice* device = nullptr;
286+
RawPacketVector* capturedPackets = nullptr;
287+
};
288+
289+
// A noop function to be used when no callback is set
290+
void onPacketArrivesNoop(uint8_t* user, const pcap_pkthdr* pkthdr, const uint8_t* packet)
291+
{}
292+
293+
// @brief Wraps the raw packet data into a RawPacket instance and calls the user callback
294+
// @param user A pointer to a CaptureContext instance
295+
// @param pkthdr A pointer to the pcap_pkthdr struct
296+
// @param packet A pointer to the raw packet data
297+
void onPacketArrivesCallback(uint8_t* user, const pcap_pkthdr* pkthdr, const uint8_t* packet)
298+
{
299+
auto* context = reinterpret_cast<CaptureContext*>(user);
300+
if (context == nullptr || context->device == nullptr || context->callback == nullptr)
301+
{
302+
PCPP_LOG_ERROR("Unable to extract PcapLiveDevice instance or callback");
303+
return;
304+
}
305+
306+
// TODO: Add exception handling to tunnel the exceptions from here to the capture thread
307+
// through the C code boundary
308+
309+
RawPacket rawPacket(packet, pkthdr->caplen, pkthdr->ts, false, context->device->getLinkType());
310+
context->callback(&rawPacket, context->device, context->userCookie);
311+
}
312+
313+
/// @brief Wraps the raw packet data into a RawPacket instance and adds it to the captured packets vector
314+
/// @param user A pointer to an AccumulatorCaptureContext instance
315+
/// @param pkthdr A pointer to the pcap_pkthdr struct
316+
/// @param packet A pointer to the raw packet data
317+
void onPacketArrivesAccumulator(uint8_t* user, const pcap_pkthdr* pkthdr, const uint8_t* packet)
318+
{
319+
auto* context = reinterpret_cast<AccumulatorCaptureContext*>(user);
320+
if (context == nullptr || context->device == nullptr || context->capturedPackets == nullptr)
321+
{
322+
PCPP_LOG_ERROR("Unable to extract PcapLiveDevice instance or captured packets vector");
323+
return;
324+
}
325+
326+
// TODO: Add exception handling to tunnel the exceptions from here to the capture thread
327+
// through the C code boundary
328+
329+
uint8_t* packetData = new uint8_t[pkthdr->caplen];
330+
std::memcpy(packetData, packet, pkthdr->caplen);
331+
auto rawPacket = std::make_unique<RawPacket>(packetData, pkthdr->caplen, pkthdr->ts, true,
332+
context->device->getLinkType());
333+
context->capturedPackets->pushBack(std::move(rawPacket));
334+
}
335+
336+
/// @brief A procedure that dispatches packets to a user-defined callback function whenever a packet arrives.
337+
///
338+
/// The procedure runs in a loop until the `stopFlag` is set to true.
339+
/// The procedure will set the `hasStarted` flag to true at the start of the procedure.
340+
///
341+
/// @param stopFlag A reference to an atomic boolean that indicates when to stop capturing packets
342+
/// @param hasStarted A reference to an atomic boolean that indicates when the capture thread has started
343+
/// @param pcapDescriptor A reference to the pcap handle on which to call pcap_dispatch
344+
/// @param context A CaptureContext instance that holds the device, callback and user cookie.
345+
void captureThreadMain(std::atomic_bool& stopFlag, std::atomic_bool& hasStarted,
346+
internal::PcapHandle const& pcapDescriptor, CaptureContext context)
347+
{
348+
PCPP_LOG_DEBUG("Started capture thread for device '" << context.device->getName() << "'");
349+
hasStarted.store(true);
350+
351+
// If the callback is null, we use a no-op handler to avoid unnecessary overhead
352+
// Statistics only capture still requires pcap_dispatch to be called, but we don't need to process
353+
// packets.
354+
pcap_handler callbackHandler = context.callback ? onPacketArrivesCallback : onPacketArrivesNoop;
355+
356+
while (!stopFlag.load())
357+
{
358+
if (pcap_dispatch(pcapDescriptor.get(), -1, callbackHandler, reinterpret_cast<uint8_t*>(&context)) ==
359+
-1)
360+
{
361+
PCPP_LOG_ERROR("pcap_dispatch returned an error: " << pcapDescriptor.getLastError());
362+
stopFlag.store(true);
363+
}
364+
}
365+
366+
PCPP_LOG_DEBUG("Ended capture thread for device '" << context.device->getName() << "'");
367+
}
368+
369+
/// @brief A procedure that accumulates captured packets into a vector.
370+
///
371+
/// The procedure runs in a loop until the `stopFlag` is set to true.
372+
/// The procedure will set the `hasStarted` flag to true at the start of the procedure.
373+
///
374+
/// @param stopFlag A reference to an atomic boolean that indicates when to stop capturing packets
375+
/// @param hasStarted A reference to an atomic boolean that indicates when the capture thread has started
376+
/// @param pcapDescriptor A reference to the pcap handle on which to call pcap_dispatch
377+
/// @param context An AccumulatorCaptureContext instance that holds the device and the captured packets vector.
378+
void captureThreadMainAccumulator(std::atomic_bool& stopFlag, std::atomic_bool& hasStarted,
379+
internal::PcapHandle const& pcapDescriptor, AccumulatorCaptureContext context)
380+
{
381+
PCPP_LOG_DEBUG("Started capture thread for device '" << context.device->getName() << "'");
382+
hasStarted.store(true);
383+
while (!stopFlag.load())
384+
{
385+
if (pcap_dispatch(pcapDescriptor.get(), 100, onPacketArrivesAccumulator,
386+
reinterpret_cast<uint8_t*>(&context)) == -1)
387+
{
388+
PCPP_LOG_ERROR("pcap_dispatch returned an error: " << pcapDescriptor.getLastError());
389+
stopFlag.store(true);
390+
}
391+
}
392+
393+
PCPP_LOG_DEBUG("Ended capture thread for device '" << context.device->getName() << "'");
394+
}
275395
} // namespace
276396

277397
PcapLiveDevice::PcapLiveDevice(DeviceInterfaceDetails interfaceDetails, bool calculateMTU, bool calculateMacAddress,
@@ -309,50 +429,15 @@ namespace pcpp
309429
m_CaptureThreadStarted = false;
310430
m_StopThread = false;
311431
m_CaptureThread = {};
312-
m_cbOnPacketArrives = nullptr;
313432
m_cbOnPacketArrivesBlockingMode = nullptr;
314433
m_cbOnPacketArrivesBlockingModeUserCookie = nullptr;
315-
m_cbOnPacketArrivesUserCookie = nullptr;
316-
m_CaptureCallbackMode = true;
317-
m_CapturedPackets = nullptr;
318434
if (calculateMacAddress)
319435
{
320436
setDeviceMacAddress();
321437
PCPP_LOG_DEBUG(" MAC addr: " << m_MacAddress);
322438
}
323439
}
324440

325-
void PcapLiveDevice::onPacketArrives(uint8_t* user, const struct pcap_pkthdr* pkthdr, const uint8_t* packet)
326-
{
327-
PcapLiveDevice* pThis = reinterpret_cast<PcapLiveDevice*>(user);
328-
if (pThis == nullptr)
329-
{
330-
PCPP_LOG_ERROR("Unable to extract PcapLiveDevice instance");
331-
return;
332-
}
333-
334-
RawPacket rawPacket(packet, pkthdr->caplen, pkthdr->ts, false, pThis->getLinkType());
335-
336-
if (pThis->m_cbOnPacketArrives != nullptr)
337-
pThis->m_cbOnPacketArrives(&rawPacket, pThis, pThis->m_cbOnPacketArrivesUserCookie);
338-
}
339-
340-
void PcapLiveDevice::onPacketArrivesNoCallback(uint8_t* user, const struct pcap_pkthdr* pkthdr,
341-
const uint8_t* packet)
342-
{
343-
PcapLiveDevice* pThis = reinterpret_cast<PcapLiveDevice*>(user);
344-
if (pThis == nullptr)
345-
{
346-
PCPP_LOG_ERROR("Unable to extract PcapLiveDevice instance");
347-
return;
348-
}
349-
350-
uint8_t* packetData = new uint8_t[pkthdr->caplen];
351-
memcpy(packetData, packet, pkthdr->caplen);
352-
RawPacket* rawPacketPtr = new RawPacket(packetData, pkthdr->caplen, pkthdr->ts, true, pThis->getLinkType());
353-
pThis->m_CapturedPackets->pushBack(rawPacketPtr);
354-
}
355-
356441
void PcapLiveDevice::onPacketArrivesBlockingMode(uint8_t* user, const struct pcap_pkthdr* pkthdr,
357442
const uint8_t* packet)
358443
{
@@ -371,37 +456,6 @@ namespace pcpp
371456
pThis->m_StopThread = true;
372457
}
373458

374-
void PcapLiveDevice::captureThreadMain()
375-
{
376-
PCPP_LOG_DEBUG("Started capture thread for device '" << m_InterfaceDetails.name << "'");
377-
m_CaptureThreadStarted = true;
378-
379-
if (m_CaptureCallbackMode)
380-
{
381-
while (!m_StopThread)
382-
{
383-
if (pcap_dispatch(m_PcapDescriptor.get(), -1, onPacketArrives, reinterpret_cast<uint8_t*>(this)) == -1)
384-
{
385-
PCPP_LOG_ERROR("pcap_dispatch returned an error: " << m_PcapDescriptor.getLastError());
386-
m_StopThread = true;
387-
}
388-
}
389-
}
390-
else
391-
{
392-
while (!m_StopThread)
393-
{
394-
if (pcap_dispatch(m_PcapDescriptor.get(), 100, onPacketArrivesNoCallback,
395-
reinterpret_cast<uint8_t*>(this)) == -1)
396-
{
397-
PCPP_LOG_ERROR("pcap_dispatch returned an error: " << m_PcapDescriptor.getLastError());
398-
m_StopThread = true;
399-
}
400-
}
401-
}
402-
PCPP_LOG_DEBUG("Ended capture thread for device '" << m_InterfaceDetails.name << "'");
403-
}
404-
405459
internal::PcapHandle PcapLiveDevice::doOpen(const DeviceConfiguration& config)
406460
{
407461
char errbuf[PCAP_ERRBUF_SIZE] = { '\0' };
@@ -654,11 +708,13 @@ namespace pcpp
654708
return false;
655709
}
656710

657-
m_CaptureCallbackMode = true;
658-
m_cbOnPacketArrives = std::move(onPacketArrives);
659-
m_cbOnPacketArrivesUserCookie = onPacketArrivesUserCookie;
711+
CaptureContext context;
712+
context.device = this;
713+
context.callback = std::move(onPacketArrives);
714+
context.userCookie = onPacketArrivesUserCookie;
660715

661-
m_CaptureThread = std::thread(&pcpp::PcapLiveDevice::captureThreadMain, this);
716+
m_CaptureThread = std::thread(&captureThreadMain, std::ref(m_StopThread), std::ref(m_CaptureThreadStarted),
717+
std::ref(m_PcapDescriptor), std::move(context));
662718

663719
// Wait thread to be start
664720
// C++20 = m_CaptureThreadStarted.wait(true);
@@ -710,11 +766,15 @@ namespace pcpp
710766
return false;
711767
}
712768

713-
m_CapturedPackets = &capturedPacketsVector;
714-
m_CapturedPackets->clear();
769+
capturedPacketsVector.clear();
770+
771+
AccumulatorCaptureContext context;
772+
context.device = this;
773+
context.capturedPackets = &capturedPacketsVector;
774+
775+
m_CaptureThread = std::thread(&captureThreadMainAccumulator, std::ref(m_StopThread),
776+
std::ref(m_CaptureThreadStarted), std::ref(m_PcapDescriptor), std::move(context));
715777

716-
m_CaptureCallbackMode = false;
717-
m_CaptureThread = std::thread(&pcpp::PcapLiveDevice::captureThreadMain, this);
718778
// Wait thread to be start
719779
// C++20 = m_CaptureThreadStarted.wait(true);
720780
while (m_CaptureThreadStarted != true)
@@ -752,8 +812,6 @@ namespace pcpp
752812
PCPP_LOG_ERROR("Failed to prepare capture: " << ex.what());
753813
return 0;
754814
}
755-
m_cbOnPacketArrives = nullptr;
756-
m_cbOnPacketArrivesUserCookie = nullptr;
757815

758816
m_cbOnPacketArrivesBlockingMode = std::move(onPacketArrives);
759817
m_cbOnPacketArrivesBlockingModeUserCookie = userCookie;

0 commit comments

Comments
 (0)