/// <summary> /// 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 /// </summary> /// <param name="timeout"> /// 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 /// </param> /// <returns>true if poll was successfull and we have data to read, false otherwise</returns> protected internal bool PollFileDescriptor(int timeout = 500) { if (FileDescriptor < 0) { // Either this is a File Capture, or Windows // Assume we have data to read return(true); } var pollFds = new Posix.Pollfd[1]; pollFds[0].fd = FileDescriptor; pollFds[0].events = Posix.PollEvents.POLLPRI | Posix.PollEvents.POLLIN; var result = Posix.Poll(pollFds, (uint)pollFds.Length, timeout); // if we have no poll results, we don't have anything to read // -1 means error // 0 means timeout // non-negative means we got something return(result != 0); }
/// <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); }