public static byte[] Read(int fd, int count, int timeout, Func <bool> shouldCancel) { #if !PLATFORM_LINUX throw new NotSupportedException("This API is available on Linux only!"); #else int pollResult; var pollData = new Pollfd { fd = fd, events = PollEvents.POLLIN }; do { pollResult = Syscall.poll(new [] { pollData }, timeout); }while(UnixMarshal.ShouldRetrySyscall(pollResult) && !shouldCancel()); if (pollResult > 0) { return(Read(fd, count)); } else { return(null); } #endif }
public void Run() { Thread m_signalThread = new Thread(SignalThread); m_signalThread.Start(); Pollfd[] fds = new Pollfd[2]; while (m_exit == false) { fds[0].fd = Mono.Unix.UnixStream.StandardInputFileDescriptor; fds[0].events = PollEvents.POLLIN; fds[0].revents = 0; fds[1].fd = m_netPipe.Reading.Handle; fds[1].events = PollEvents.POLLIN; fds[1].revents = 0; int ret = Syscall.poll(fds, -1); if (ret == 0) { //ChiConsole.Prompt = String.Format("pr{0}> ", z++); ChiConsole.WriteLine("timeout"); } else if (ret > 0) { if (fds[0].revents != 0) { m_textConsole.ReadChars(); string str; while ((str = m_textConsole.GetLine()) != null) { //m_textConsole.WriteLine("Tuli {0}", str); HandleInput(str); } } if (fds[1].revents != 0) { m_netPipe.Reading.ReadByte(); m_synchronizedInvoke.DispatchInvokes(); } } } Dbg.WriteLine("Exiting"); m_sigThreadStop = true; if (m_signalThread.Join(1000) == false) { m_signalThread.Abort(); } m_textConsole.UnInit(); }
private bool IsDataAvailable(int timeout, out int pollResult) { var pollData = new Pollfd { fd = master, events = PollEvents.POLLIN }; do { pollResult = Syscall.poll(new [] { pollData }, timeout); }while(!disposed && UnixMarshal.ShouldRetrySyscall(pollResult)); return(pollResult > 0); }
private unsafe void waitInterrupt(int file) { var pfs = new Pollfd(); pfs.fd = file; pfs.events = PollEvents.POLLPRI | PollEvents.POLLERR; pfs.revents = 0; var buf = new byte[2]; fixed(byte *pb = buf) { var r = Syscall.poll(new[] { pfs }, -1); var res2 = (int)Syscall.pread(file, pb, (ulong)1, 0); } }
public static byte[] ReadDataWithTimeout(int fd, int count, int timeout, Func <bool> shouldCancel) { int pollResult; var pollData = new Pollfd { fd = fd, events = PollEvents.POLLIN }; do { pollResult = Syscall.poll(new [] { pollData }, timeout); }while(UnixMarshal.ShouldRetrySyscall(pollResult) && !shouldCancel()); if (pollResult > 0) { return(ReadData(fd, count)); } else { return(null); } }
public X11Display (IntPtr display) { if (display == IntPtr.Zero) { throw new ArgumentNullException("Display", "Could not open display (X-Server required. Check your DISPLAY environment variable)"); } this.display = display; // Debugging support if (Environment.GetEnvironmentVariable ("MONO_XSYNC") != null) { Xlib.XSynchronize (display, true); } if (Environment.GetEnvironmentVariable ("MONO_XEXCEPTIONS") != null) { ErrorExceptions = true; } atoms = new X11Atoms (this); DoubleClickInterval = 500; HoverState.Interval = 500; HoverState.Timer = new Timer(); HoverState.Timer.Enabled = false; HoverState.Timer.Interval = HoverState.Interval; HoverState.Timer.Tick += new EventHandler(MouseHover); HoverState.Size = new Size(4, 4); HoverState.X = -1; HoverState.Y = -1; ActiveWindow = null; FocusWindow = null; ModalWindows = new Stack(3); MouseState = MouseButtons.None; MousePosition = new Point(0, 0); Caret.Timer = new Timer(); Caret.Timer.Interval = 500; // FIXME - where should this number come from? Caret.Timer.Tick += new EventHandler(CaretCallback); // XXX multiscreen work here root_hwnd = new X11RootHwnd (this, Xlib.XRootWindow (display, DefaultScreen)); // XXX do we need a per-screen foster parent? // Create the foster parent foster_hwnd = new X11Hwnd (this, Xlib.XCreateSimpleWindow (display, root_hwnd.WholeWindow, 0, 0, 1, 1, 4, UIntPtr.Zero, UIntPtr.Zero)); pollfds = new Pollfd [1]; pollfds [0] = new Pollfd (); pollfds [0].fd = Xlib.XConnectionNumber (display); pollfds [0].events = PollEvents.POLLIN; Keyboard = new X11Keyboard(display, foster_hwnd.Handle); Dnd = new X11Dnd (display, Keyboard); ErrorExceptions = false; // Handle any upcoming errors ErrorHandler = new XErrorHandler (HandleError); Xlib.XSetErrorHandler (ErrorHandler); X11DesktopColors.Initialize(); // XXX we need to figure out how to make this display specific? // Disable keyboard autorepeat try { Xlib.XkbSetDetectableAutoRepeat (display, true, IntPtr.Zero); detectable_key_auto_repeat = true; } catch { Console.Error.WriteLine ("Could not disable keyboard auto repeat, will attempt to disable manually."); detectable_key_auto_repeat = false; } // we re-set our error handler here, X11DesktopColor stuff might have stolen it (gtk does) Xlib.XSetErrorHandler (ErrorHandler); // create our event thread (just sits on the X socket waiting for events) event_thread = new Thread (new ThreadStart (XEventThread)); event_thread.IsBackground = true; event_thread.Start (); }
public static bool TryCopy (IntPtr source, out Pollfd destination) { return ToPollfd (source, out destination) == 0; }
private static extern int ToPollfd (IntPtr source, out Pollfd destination);
internal void SetDisplay(IntPtr display_handle) { if (display_handle != IntPtr.Zero) { Hwnd hwnd; if ((DisplayHandle != IntPtr.Zero) && (FosterParent != IntPtr.Zero)) { hwnd = Hwnd.ObjectFromHandle(FosterParent); XDestroyWindow(DisplayHandle, FosterParent); hwnd.Dispose(); } if (DisplayHandle != IntPtr.Zero) { XCloseDisplay(DisplayHandle); } DisplayHandle=display_handle; // We need to tell System.Drawing our DisplayHandle. FromHdcInternal has // been hacked to do this for us. Graphics.FromHdcInternal (DisplayHandle); // query for the render extension so // we can ignore the spurious // BadPicture errors that are // generated by cairo/render. XQueryExtension (DisplayHandle, "RENDER", ref render_major_opcode, ref render_first_event, ref render_first_error); // Debugging support if (Environment.GetEnvironmentVariable ("MONO_XSYNC") != null) { XSynchronize(DisplayHandle, true); } if (Environment.GetEnvironmentVariable ("MONO_XEXCEPTIONS") != null) { ErrorExceptions = true; } // Generic X11 setup ScreenNo = XDefaultScreen(DisplayHandle); RootWindow = XRootWindow(DisplayHandle, ScreenNo); DefaultColormap = XDefaultColormap(DisplayHandle, ScreenNo); // Create the foster parent // it is important that border_width is kept in synch with the other XCreateWindow calls FosterParent=XCreateSimpleWindow(DisplayHandle, RootWindow, 0, 0, 1, 1, 0, UIntPtr.Zero, UIntPtr.Zero); if (FosterParent==IntPtr.Zero) { Console.WriteLine("XplatUIX11 Constructor failed to create FosterParent"); } DebugHelper.WriteLine ("FosterParent created 0x{0:x}", FosterParent.ToInt32()); hwnd = new Hwnd(); hwnd.Queue = ThreadQueue(Thread.CurrentThread); hwnd.WholeWindow = FosterParent; hwnd.ClientWindow = FosterParent; // Create a HWND for RootWIndow as well, so our queue doesn't eat the events hwnd = new Hwnd(); hwnd.Queue = ThreadQueue(Thread.CurrentThread); hwnd.whole_window = RootWindow; hwnd.ClientWindow = RootWindow; // For sleeping on the X11 socket listen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 0); listen.Bind(ep); listen.Listen(1); // To wake up when a timer is ready network_buffer = new byte[10]; wake = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); wake.Connect(listen.LocalEndPoint); // Make this non-blocking, so it doesn't // deadlock if too many wakes are sent // before the wake_receive end is polled wake.Blocking = false; wake_receive = listen.Accept(); #if __MonoCS__ pollfds = new Pollfd [2]; pollfds [0] = new Pollfd (); pollfds [0].fd = XConnectionNumber (DisplayHandle); pollfds [0].events = PollEvents.POLLIN; pollfds [1] = new Pollfd (); pollfds [1].fd = wake_receive.Handle.ToInt32 (); pollfds [1].events = PollEvents.POLLIN; #endif Keyboard = new X11Keyboard(DisplayHandle, FosterParent); Dnd = new X11Dnd (DisplayHandle, Keyboard); DoubleClickInterval = 500; HoverState.Interval = 500; HoverState.Timer = new Timer(); HoverState.Timer.Enabled = false; HoverState.Timer.Interval = HoverState.Interval; HoverState.Timer.Tick += new EventHandler(MouseHover); HoverState.Size = new Size(4, 4); HoverState.X = -1; HoverState.Y = -1; ActiveWindow = IntPtr.Zero; FocusWindow = IntPtr.Zero; ModalWindows = new Stack(3); MouseState = MouseButtons.None; mouse_position = new Point(0, 0); Caret.Timer = new Timer(); Caret.Timer.Interval = 500; // FIXME - where should this number come from? Caret.Timer.Tick += new EventHandler(CaretCallback); SetupAtoms(); // Grab atom changes off the root window to catch certain WM events XSelectInput(DisplayHandle, RootWindow, new IntPtr ((int) (EventMask.PropertyChangeMask | Keyboard.KeyEventMask))); // Handle any upcoming errors ErrorHandler = new XErrorHandler(HandleError); XSetErrorHandler(ErrorHandler); } else { throw new ArgumentNullException("Display", "Could not open display (X-Server required. Check your DISPLAY environment variable)"); } }
protected override void OnInput() { System.Diagnostics.Debug.Assert(_socket != null); if (_recvBuffer == null || _recvBuffer.Capacity < _bufferSize) { _recvBuffer = new MemoryStream(_bufferSize); } _recvBuffer.Seek(0, SeekOrigin.Begin); _recvBuffer.SetLength(_recvBuffer.Capacity); byte[] buf = _recvBuffer.GetBuffer(); int offset = (int)_recvBuffer.Position; int size = (int)_recvBuffer.Length; Pollfd[] fds = new Pollfd[1]; fds[0].fd = _socket.Handle; fds[0].events = PollEvents.POLLIN; int expires = Environment.TickCount + Timeout; int wait = 0; for (;;) { try { wait = Math.Max(0, expires - Environment.TickCount); fds[0].revents = 0; int ret = Syscall.poll(fds, wait); if (UnixMarshal.ShouldRetrySyscall(ret)) { continue; } UnixMarshal.ThrowExceptionForLastErrorIf(ret); if (ret == 0) { throw new TimeoutException(); } if (ret != 1 || (fds[0].revents & PollEvents.POLLIN) == 0) { continue; } var rxLen = _socket.Read(buf, offset, size); _recvBuffer.SetLength(rxLen); if (Logger.IsDebugEnabled) { Logger.Debug("\n\n" + Utilities.HexDump(_recvBuffer)); } // Got a valid packet return; } catch (Exception ex) { Logger.Error("Unable to receive CAN packet on {0}. {1}", Interface, ex.Message); throw new SoftException(ex); } } }
private static int FromPollfd (ref Pollfd source, IntPtr destination) { throw new System.NotImplementedException(); }
/// <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); }
public static int poll (Pollfd [] fds, uint nfds, int timeout) { return -1; }
// native X display handle internal void SetDisplay (IntPtr display_handle) { if (display_handle != IntPtr.Zero) { Hwnd hwnd; if ((GdkDisplayHandle != IntPtr.Zero) && (GdkFosterParent != IntPtr.Zero)) { hwnd = Hwnd.ObjectFromHandle (gdk_x11_drawable_get_xid (GdkFosterParent)); gdk_window_destroy (GdkFosterParent); hwnd.Dispose (); } if (GdkDisplayHandle != IntPtr.Zero) { gdk_display_close (GdkDisplayHandle); } DisplayHandle = display_handle; GdkDisplayHandle = gdk_x11_lookup_xdisplay (display_handle); // We need to tell System.Drawing our DisplayHandle. FromHdcInternal has // been hacked to do this for us. Graphics.FromHdcInternal (DisplayHandle); // Debugging support if (Environment.GetEnvironmentVariable ("MONO_XSYNC") != null) { XSynchronize (DisplayHandle, true); } if (Environment.GetEnvironmentVariable ("MONO_XEXCEPTIONS") != null) { ErrorExceptions = true; } // Generic X11 setup GdkScreen = gdk_screen_get_default (); // or gdk_x11_get_default_screen ScreenNo = gdk_screen_get_number (GdkScreen); GdkRootWindow = gdk_get_default_root_window (); RootWindow = gdk_x11_drawable_get_xid (GdkRootWindow); GdkDefaultColormap = gdk_colormap_get_system (); DefaultColormap = gdk_x11_colormap_get_xcolormap (GdkDefaultColormap); VisualBestDepth = gdk_visual_get_best_depth (); //Console.WriteLine (VisualBestDepth); // Create the foster parent FosterParent = XCreateSimpleWindow (DisplayHandle, RootWindow, 0, 0, 1, 1, 4, 0, 0); GdkFosterParent = gdk_window_foreign_new (FosterParent); if (GdkFosterParent == IntPtr.Zero) { Console.WriteLine ("XplatUIX11GTK Constructor failed to create FosterParent"); } hwnd = new Hwnd (); hwnd.WholeWindow = FosterParent; hwnd.ClientWindow = FosterParent; // For sleeping on the X11 socket listen = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); IPEndPoint ep = new IPEndPoint (IPAddress.Loopback, 0); listen.Bind (ep); listen.Listen (1); // To wake up when a timer is ready network_buffer = new byte [10]; wake = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); wake.Connect (listen.LocalEndPoint); wake_receive = listen.Accept (); pollfds = new Pollfd [2]; pollfds [0] = new Pollfd (); pollfds [0].fd = XConnectionNumber (DisplayHandle); pollfds [0].events = PollEvents.POLLIN; pollfds [1] = new Pollfd (); pollfds [1].fd = wake_receive.Handle.ToInt32 (); pollfds [1].events = PollEvents.POLLIN; Keyboard = new X11Keyboard (DisplayHandle); Dnd = new X11Dnd (DisplayHandle); PostQuitState = false; DoubleClickInterval = 500; HoverState.Interval = 500; HoverState.Timer = new Timer (); HoverState.Timer.Enabled = false; HoverState.Timer.Interval = HoverState.Interval; HoverState.Timer.Tick += new EventHandler (MouseHover); HoverState.X = -1; HoverState.Y = -1; ActiveWindow = IntPtr.Zero; FocusWindow = IntPtr.Zero; ModalWindows = new Stack (3); MouseState = MouseButtons.None; MousePosition = new Point (0, 0); Caret.Timer = new Timer (); Caret.Timer.Interval = 500; // FIXME - where should this number come from? Caret.Timer.Tick += new EventHandler (CaretCallback); SetupAtoms (); // Grab atom changes off the root window to catch certain WM events gdk_window_set_events (GdkRootWindow, (int)GdkEventMask.GDK_PROPERTY_CHANGE_MASK); // Handle any upcoming errors ErrorHandler = new XErrorHandler (HandleError); XSetErrorHandler (ErrorHandler); } else { throw new ArgumentNullException ("Display", "Could not open display (X-Server required. Check your DISPLAY environment variable)"); } }
protected override void OnOutput(byte[] buf, int offset, int count) { int size = count; Pollfd[] fds = new Pollfd[1]; fds[0].fd = _socket.Handle; fds[0].events = PollEvents.POLLOUT; if (Logger.IsDebugEnabled) { Logger.Debug("\n\n" + Utilities.HexDump(buf, offset, count)); } int expires = Environment.TickCount + Timeout; int wait = 0; for (;;) { try { wait = Math.Max(0, expires - Environment.TickCount); fds[0].revents = 0; int ret = Syscall.poll(fds, wait); if (UnixMarshal.ShouldRetrySyscall(ret)) { continue; } UnixMarshal.ThrowExceptionForLastErrorIf(ret); if (ret == 0) { throw new TimeoutException(); } if (ret != 1 || (fds[0].revents & PollEvents.POLLOUT) == 0) { continue; } _socket.Write(buf, offset, size); return; } catch (Exception ex) { if (ex is TimeoutException) { Logger.Debug("Ethernet packet not sent to {0} in {1}ms, timing out.", Interface, Timeout); } else { Logger.Error("Unable to send ethernet packet to {0}. {1}", Interface, ex.Message); } throw new SoftException(ex); } } }
private static int ToPollfd (IntPtr source, out Pollfd destination) { throw new System.NotImplementedException(); }
private static extern int FromPollfd (ref Pollfd source, IntPtr destination);
protected override void OnOutput(BitwiseStream data) { if (Logger.IsDebugEnabled) { Logger.Debug("\n\n" + Utilities.HexDump(data)); } long count = data.Length; //var buffer = new byte[MaxMTU]; var buffer = new byte[CAN_MTU]; int size = data.Read(buffer, 0, buffer.Length); Pollfd[] fds = new Pollfd[1]; fds[0].fd = _socket.Handle; fds[0].events = PollEvents.POLLOUT; int expires = Environment.TickCount + Timeout; int wait = 0; for (;;) { try { wait = Math.Max(0, expires - Environment.TickCount); fds[0].revents = 0; int ret = Syscall.poll(fds, wait); if (UnixMarshal.ShouldRetrySyscall(ret)) { continue; } UnixMarshal.ThrowExceptionForLastErrorIf(ret); if (ret == 0) { throw new TimeoutException(); } if (ret != 1 || (fds[0].revents & PollEvents.POLLOUT) == 0) { continue; } //_socket.Write(buffer, 0, size); _socket.Write(buffer, 0, CAN_MTU); if (count != size) { throw new Exception(string.Format("Only sent {0} of {1} byte packet.", size, count)); } return; } catch (Exception ex) { Logger.Error("Unable to send CAN packet to {0}. {1}", Interface, ex.Message); throw new SoftException(ex); } } }
public static bool TryCopy (ref Pollfd source, IntPtr destination) { return FromPollfd (ref source, destination) == 0; }
/// <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); }
public IDisposable Connect() { if (monitor != null) { throw new InvalidOperationException("already connected"); } monitor = new Monitor(udev); monitor.AddMatchSubsystem("hidraw"); monitor.EnableReceiving(); var tokenSource = new CancellationTokenSource(); var token = tokenSource.Token; Task.Run(() => { try { var enumerator = new Enumerator(udev); enumerator.AddMatchSubsystem("hidraw"); enumerator.ScanDevices(); foreach (var device in enumerator) { if (token.IsCancellationRequested) { break; } var hids = TryGetHidDevices(device); if (hids == null) { continue; } foreach (var hid in hids) { subject.OnNext(hid); } } var pollfds = new Pollfd[] { new Pollfd { fd = monitor.Fd, events = PollEvents.POLLIN } }; while (!token.IsCancellationRequested) { // FIXME: it would be nice if we didn't wake up every 100ms // not sure how to interrupt a system call though // pinvoke pthread_kill() maybe? var ret = Syscall.poll(pollfds, 100); if (ret == -1) { var err = Stdlib.GetLastError(); if (err == Errno.EINTR) { continue; } UnixMarshal.ThrowExceptionForError(err); } if (token.IsCancellationRequested) { break; } if (ret == 0) { // timed out continue; } if (pollfds[0].revents.HasFlag(PollEvents.POLLNVAL)) { // monitor file descriptor is closed, monitor must // have been disposed, so complete gracefully break; } var device = monitor.TryReceiveDevice(); var hids = TryGetHidDevices(device); if (hids == null) { continue; } foreach (var hid in hids) { subject.OnNext(hid); } } subject.OnCompleted(); } catch (Exception ex) { subject.OnError(ex); } finally { monitor.Dispose(); monitor = null; } }, token); return(Disposable.Create(() => tokenSource.Cancel())); }