/// <summary> /// The capture thread /// </summary> protected virtual void CaptureThread() { if (!Opened) { throw new DeviceNotReadyException("Capture called before PcapDevice.Open()"); } var usePoll = (this is LibPcapLiveDevice) && isLibPcap && MonoUnixFound; // unix specific code int captureFileDescriptor = 0; if (usePoll) { // retrieve the file descriptor of the adapter for use with poll() captureFileDescriptor = LibPcapSafeNativeMethods.pcap_fileno(PcapHandle); if (captureFileDescriptor == -1) { SendCaptureStoppedEvent(CaptureStoppedEventStatus.ErrorWhileCapturing); return; } } LibPcapSafeNativeMethods.pcap_handler Callback = new LibPcapSafeNativeMethods.pcap_handler(PacketHandler); // unix specific code #if UseMonoUnixNativeDirectly Pollfd[] pollFds = new Pollfd[1]; #else System.Array pollFds = null; object[] PollParameters = null; #endif // Timeout chosen to allow the capture thread to loop frequently enough // to enable it to properly exit when the user requests it to but // infrequently enough to cause any noticable performance overhead int millisecondTimeout = 500; if (usePoll) { #if UseMonoUnixNativeDirectly pollFds[0].fd = captureFileDescriptor; pollFds[0].events = PollEvents.POLLPRI | Mono.Unix.Native.PollEvents.POLLIN; #else FieldInfo field; pollFds = Array.CreateInstance(PollfdType, 1); // create a PollFd struct instance var pollFd = Activator.CreateInstance(PollfdType); // set the descriptor field field = PollfdType.GetField("fd"); field.SetValue(pollFd, captureFileDescriptor); // set the events field short eventValue = (short)(POLLIN | POLLPRI); // mask the two together field = PollfdType.GetField("events"); field.SetValue(pollFd, eventValue); // set the Pollfd entry pollFds.SetValue(pollFd, 0); // setup the parameters we will pass to the poll() method PollParameters = new object[2]; PollParameters[0] = pollFds; PollParameters[1] = millisecondTimeout; #endif } while (!shouldCaptureThreadStop) { // unix specific code, we want to poll for packets // otherwise if we call pcap_dispatch() the read() will block // and won't resume until a packet arrives OR until a signal // occurs if (usePoll) { // block here #if UseMonoUnixNativeDirectly var result = Mono.Unix.Native.Syscall.poll(pollFds, millisecondTimeout); #else object o = SyscallType.InvokeMember("poll", BindingFlags.InvokeMethod, Type.DefaultBinder, null, PollParameters); int result = (int)o; #endif // if we have no poll results, just loop if (result <= 0) { continue; } // fall through here to the pcap_dispatch() call } int res = LibPcapSafeNativeMethods.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(CaptureStoppedEventStatus.CompletedWithoutError); 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 CaptureFileReaderDevice) { SendCaptureStoppedEvent(CaptureStoppedEventStatus.CompletedWithoutError); return; } break; } case Pcap.LOOP_EXIT_WITH_ERROR: // An error occurred whilst capturing. SendCaptureStoppedEvent(CaptureStoppedEventStatus.CompletedWithoutError); return; default: // This can only be triggered by a bug in libpcap. throw new PcapException("Unknown pcap_loop exit status."); } } else // res > 0 { // if we aren't capturing infinitely we need to account for // the packets that we read if (m_pcapPacketCount != Pcap.InfinitePacketCount) { // take away for the packets read if (m_pcapPacketCount >= res) { m_pcapPacketCount -= res; } else { m_pcapPacketCount = 0; } // no more packets to capture, we are finished capturing if (m_pcapPacketCount == 0) { SendCaptureStoppedEvent(CaptureStoppedEventStatus.CompletedWithoutError); return; } } } } SendCaptureStoppedEvent(CaptureStoppedEventStatus.CompletedWithoutError); }
/// <summary> /// The capture thread /// </summary> protected virtual void CaptureThread(CancellationToken cancellationToken) { if (!Opened) { throw new DeviceNotReadyException("Capture called before PcapDevice.Open()"); } var Callback = new LibPcapSafeNativeMethods.pcap_handler(PacketHandler); Posix.Pollfd[] pollFds = null; // unix specific code if (UsePosixPoll) { // retrieve the file descriptor of the adapter for use with poll() var captureFileDescriptor = LibPcapSafeNativeMethods.pcap_fileno(PcapHandle); if (captureFileDescriptor == -1) { SendCaptureStoppedEvent(CaptureStoppedEventStatus.ErrorWhileCapturing); return; } pollFds = new Posix.Pollfd[1]; pollFds[0].fd = captureFileDescriptor; pollFds[0].events = Posix.PollEvents.POLLPRI | Posix.PollEvents.POLLIN; } while (!cancellationToken.IsCancellationRequested) { // unix specific code, we want to poll for packets // otherwise if we call pcap_dispatch() the read() will block // and won't resume until a packet arrives OR until a signal // occurs if (pollFds != null) { // Timeout chosen to allow the capture thread to loop frequently enough // to enable it to properly exit when the user requests it to but // infrequently enough to cause any noticable performance overhead const int millisecondTimeout = 500; // block here var result = Posix.Poll(pollFds, (uint)pollFds.Length, millisecondTimeout); // if we have no poll results, just loop if (result <= 0) { continue; } // fall through here to the pcap_dispatch() call } int res = LibPcapSafeNativeMethods.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(CaptureStoppedEventStatus.CompletedWithoutError); 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 CaptureFileReaderDevice) { SendCaptureStoppedEvent(CaptureStoppedEventStatus.CompletedWithoutError); return; } break; } case Pcap.LOOP_EXIT_WITH_ERROR: // An error occurred whilst capturing. SendCaptureStoppedEvent(CaptureStoppedEventStatus.ErrorWhileCapturing); return; default: // This can only be triggered by a bug in libpcap. throw new PcapException("Unknown pcap_loop exit status."); } } else // res > 0 { // if we aren't capturing infinitely we need to account for // the packets that we read if (m_pcapPacketCount != Pcap.InfinitePacketCount) { // take away for the packets read if (m_pcapPacketCount >= res) { m_pcapPacketCount -= res; } else { m_pcapPacketCount = 0; } // no more packets to capture, we are finished capturing if (m_pcapPacketCount == 0) { SendCaptureStoppedEvent(CaptureStoppedEventStatus.CompletedWithoutError); return; } } } } SendCaptureStoppedEvent(CaptureStoppedEventStatus.CompletedWithoutError); }