/// <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);
        }
예제 #2
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);
        }