using System;
using System.Threading;
namespace SharpPcap
{
public partial class PcapDevice
{
private Thread captureThread;
private bool shouldCaptureThreadStop;
///
/// Return a value indicating if the capturing process of this adapter is started
///
public virtual bool Started
{
get{ return (captureThread != null); }
}
///
/// Starts the capturing process
///
public virtual void StartCapture()
{
if (!Started)
{
if (!Opened)
throw new PcapDeviceNotReadyException("Can't start capture, the pcap device is not opened.");
shouldCaptureThreadStop = false;
captureThread = new Thread(new ThreadStart(this.CaptureThread));
captureThread.Start();
}
}
///
/// Stops the capture process
///
/// Throws an exception if the stop capture timeout is exceeded and the
/// capture thread was aborted
///
public virtual void StopCapture()
{
TimeSpan joinTimeout = new TimeSpan(0, 0, 1);
if (Started)
{
shouldCaptureThreadStop = true;
if(!captureThread.Join(joinTimeout))
{
captureThread.Abort();
captureThread = null;
throw new PcapException("captureThread was aborted after " + joinTimeout.ToString());
}
captureThread = null; // otherwise we will always return true from PcapDevice.Started
}
}
///
/// Captures packets on this network device. This method will block
/// until capturing is finished.
///
/// The number of packets to be captured.
/// Value of '-1' means infinite.
public void Capture(int packetCount)
{
m_pcapPacketCount = packetCount;
CaptureThread();
m_pcapPacketCount = Pcap.INFINITE;;
}
private void CaptureThread()
{
if (!Opened)
throw new PcapDeviceNotReadyException("Capture called before PcapDevice.Open()");
SafeNativeMethods.pcap_handler Callback = new SafeNativeMethods.pcap_handler(PacketHandler);
while(!shouldCaptureThreadStop)
{
int res = SafeNativeMethods.pcap_dispatch(PcapHandle, m_pcapPacketCount, Callback, IntPtr.Zero);
// pcap_dispatch() returns the number of packets read or, a status value if the value
// is negative
if(res <= 0)
{
switch (res) // Check pcap loop status results and notify upstream.
{
case Pcap.LOOP_USER_TERMINATED: // User requsted loop termination with StopCapture()
SendCaptureStoppedEvent(false);
return;
case Pcap.LOOP_COUNT_EXHAUSTED: // m_pcapPacketCount exceeded (successful exit)
{
// NOTE: pcap_dispatch() returns 0 when a timeout occurrs so to prevent timeouts
// from causing premature exiting from the capture loop we only consider
// exhausted events to cause an escape from the loop when they are from
// offline devices, ie. files read from disk
if(this is PcapOfflineDevice)
{
SendCaptureStoppedEvent(false);
return;
}
break;
}
case Pcap.LOOP_EXIT_WITH_ERROR: // An error occoured whilst capturing.
SendCaptureStoppedEvent(true);
return;
default: // This can only be triggered by a bug in libpcap.
throw new PcapException("Unknown pcap_loop exit status.");
}
}
}
SendCaptureStoppedEvent(false);
}
}
}