[ros-dev] [ros-diffs] [gschneider] 36737: RosDbg Part 3/3: - Named pipe implementation based on .net namespace IO.Pipes with support of threads - Previous win32 test version would strip random characters from debug messages and crash on entering kdbg (related t

gedmurphy gedmurphy at gmail.com
Mon Oct 13 12:11:16 CEST 2008


I'd originally refrained from doing it this way, using pinvoke instead to keep .net 2.0 compatibility.
Using classes such as NamedPipeServerStream forces a .net 3.5 dependency. Is this ok with everyone?

Ged.



-----Original Message-----
From: ros-diffs-bounces at reactos.org [mailto:ros-diffs-bounces at reactos.org] On Behalf Of gschneider at svn.reactos.org
Sent: 12 October 2008 22:56
To: ros-diffs at reactos.org
Subject: [ros-diffs] [gschneider] 36737: RosDbg Part 3/3: - Named pipe implementation based on .net namespace IO.Pipes with support of threads - Previous win32 test version would strip random characters from debug messages and crash on entering kdbg (related to .n

Author: gschneider
Date: Sun Oct 12 16:55:50 2008
New Revision: 36737

URL: http://svn.reactos.org/svn/reactos?rev=36737&view=rev
Log:
RosDbg Part 3/3:
- Named pipe implementation based on .net namespace IO.Pipes with support of threads
- Previous win32 test version would strip random characters from debug messages and crash on entering kdbg (related to .net ReadFile approach)
- Works with QEMU (Client mode), VirtualBox (Client and Server), VMware Server (Client and Server)
- Usually faster than pure serial connection mode

Known bugs: 
- Input to kdbg using /KDSERIAL is not displayed until enter pressed (but input works)
- Reconnect issues, depending on virtual machine behaviour

Modified:
    trunk/tools/reactosdbg/Pipe/namedpipe.cs
    trunk/tools/reactosdbg/Pipe/serialpipe.cs

Modified: trunk/tools/reactosdbg/Pipe/namedpipe.cs
URL: http://svn.reactos.org/svn/reactos/trunk/tools/reactosdbg/Pipe/namedpipe.cs?rev=36737&r1=36736&r2=36737&view=diff
==============================================================================
--- trunk/tools/reactosdbg/Pipe/namedpipe.cs [iso-8859-1] (original)
+++ trunk/tools/reactosdbg/Pipe/namedpipe.cs [iso-8859-1] Sun Oct 12 16:55:50 2008
@@ -1,227 +1,205 @@
 using System;
+using System.Collections.Generic;
+using System.ComponentModel;
 using System.IO;
-using System.ComponentModel;
+using System.IO.Pipes;
 using System.Runtime.InteropServices;
-
+using System.Text;
+using System.Threading;
 
 namespace AbstractPipe
 {
-    class Kernel32
+    public enum ConnectionMode
     {
-        [DllImport("kernel32.dll", SetLastError = true)]
-        public static extern IntPtr CreateNamedPipe(
-            String lpName,
-            OpenMode dwOpenMode,
-            uint dwPipeMode,
-            uint nMaxInstances,
-            uint nOutBufferSize,
-            uint nInBufferSize,
-            DefaultTimeout nDefaultTimeOut,
-            IntPtr pipeSecurityDescriptor
-            );
-
-        [DllImport("kernel32.dll", SetLastError = true)]
-        public static extern bool ConnectNamedPipe(
-            IntPtr hHandle,
-            IntPtr lpOverlapped
-            );
-
-        [DllImport("kernel32.dll", SetLastError = true)]
-        public static extern bool ReadFile(
-            IntPtr hHandle,
-            byte[] lpBuffer,
-            uint nNumberOfBytesToRead,
-            ref uint lpNumberOfBytesRead,
-            IntPtr lpOverlapped
-            );
-
-        [DllImport("kernel32.dll", SetLastError = true)]
-        public static extern bool WriteFile(
-            IntPtr hHandle,
-            byte[] lpBuffer,
-            uint nNumberOfBytesToWrite,
-            ref uint lpNumberOfBytesWritten,
-            IntPtr lpOverlapped
-            );
-
-        [DllImport("kernel32.dll", SetLastError = true)]
-        public static extern bool CloseHandle(
-            IntPtr hHandle);
-
-        [DllImport("kernel32.dll", SetLastError = true)]
-        public static extern uint GetLastError();
-
-        [DllImport("kernel32.dll", SetLastError = true)]
-        public static extern bool DisconnectNamedPipe(
-            IntPtr hHandle);
-
-        [DllImport("kernel32.dll", SetLastError = true)]
-        public static extern bool FlushFileBuffers(IntPtr handle);
+        MODE_CLIENT = 0x00000000,
+        MODE_SERVER = 0x00000001,
+        MODE_AUTO   = 0x00000002
     }
 
-    [StructLayout(LayoutKind.Sequential)]
-    public class Overlapped
+    public class NamedPipe : Pipe
     {
-    }
-
-    public enum OpenMode : uint
-    {
-        PIPE_ACCESS_INBOUND = 0x00000001,
-        PIPE_ACCESS_OUTBOUND = 0x00000002,
-        PIPE_ACCESS_DUPLEX = 0x00000003,
-        FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000,
-        FILE_FLAG_OVERLAPPED = 0x40000000,
-        FILE_FLAG_WRITE_THROUGH = 0x80000000
-    }
-
-    public enum DefaultTimeout : uint
-    {
-        NMPWAIT_USE_DEFAULT_WAIT = 0x00000000,
-        NMPWAIT_NOWAIT = 0x00000001,
-        NMPWAIT_WAIT_FOREVER = 0xffffffff
-    }
-
-    [StructLayout(LayoutKind.Sequential)]
-    public struct SECURITY_ATTRIBUTES
-    {
-        public int nLength;
-        public IntPtr lpSecurityDescriptor;
-        public int bInheritHandle;
-    }
-
-    public class NamedPipe// : Pipe
-    {
-        private const Int32 INVALID_HANDLE_VALUE = -1;
-        private const ulong ERROR_PIPE_CONNECTED = 535;
-
-        private IntPtr handle;
-        //FileAccess mode;
+        public const int PIPE_SIZE = 1024;
+
+        private PipeStream ioStream; /* stream for io operations */
+        private String wCommand; /* buffer of a single command line */
+        private List<String> cmdList; /*list of commands pending to be written */
+
+        public event PipeReceiveEventHandler PipeReceiveEvent;
+        public event PipeErrorEventHandler PipeErrorEvent;
+
+        private static ManualResetEvent newWriteData = new ManualResetEvent(false);
 
         public NamedPipe()
         {
-            handle = IntPtr.Zero;
-        }
-
-        public IntPtr Create(string name)
-        {
-            handle = Kernel32.CreateNamedPipe(name,
-                                              OpenMode.PIPE_ACCESS_DUPLEX | OpenMode.FILE_FLAG_OVERLAPPED,
-                                              0,
-                                              1,
-                                              100,
-                                              100,
-                                              DefaultTimeout.NMPWAIT_WAIT_FOREVER,
-                                              IntPtr.Zero);
-            if (handle.ToInt32() == INVALID_HANDLE_VALUE)
-            {
-                throw new Win32Exception("Error creating named pipe " + name + " . Internal error: " + Marshal.GetLastWin32Error().ToString());
-            }
-
-            return handle;
-        }
-
-        public void Disconnect()
-        {
-            Kernel32.DisconnectNamedPipe(handle);
+            cmdList = new List<string>();
+        }
+
+        public bool CreateServerPipe(string name)
+        {
+            /* create a pipe and wait for a client */
+            NamedPipeServerStream sStream = new NamedPipeServerStream(name, PipeDirection.InOut, 1, 
+                PipeTransmissionMode.Byte, PipeOptions.Asynchronous, PIPE_SIZE, PIPE_SIZE);
+            sStream.WaitForConnection();
+
+            if (sStream.IsConnected)
+            {
+                ioStream = sStream;
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+       
+        public bool CreateClientPipe(string name)
+        {
+            /* try to connect as a client */
+            /* (QEMU -serial pipe or VMware in pipe server mode) */
+            try
+            {
+                NamedPipeClientStream cStream = new NamedPipeClientStream(".", name, PipeDirection.InOut, PipeOptions.Asynchronous);
+                cStream.Connect(100);
+
+                if (cStream.IsConnected)
+                {
+                    ioStream = cStream;
+                    return true;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+            catch (Exception)
+            {
+                return false;
+            }
+        }
+
+        public bool CreatePipe(string name, ConnectionMode mode)
+        {
+            if (name == "" || name == null)
+            {
+                return false;
+            }
+            switch (mode)
+            {
+                case ConnectionMode.MODE_AUTO:
+                    //check if pipe exists, if not create server pipe, wait certain time, check if pipe...
+                    //TODO: server-client lookup should time out
+                    while (true)
+                    {
+                        if (CreateClientPipe(name))
+                        {
+                            break;
+                        }
+                        if (CreateServerPipe(name))
+                        {
+                            break;
+                        }
+                    }
+                    return true; 
+
+                case ConnectionMode.MODE_CLIENT:
+                    while (!CreateClientPipe(name)) ;
+                    
+                    /* pipe open, everything fine */
+                    return true;
+
+                case ConnectionMode.MODE_SERVER:
+                    if (CreateServerPipe(name))
+                    {
+                        /* wait for a client*/
+                        
+                        return true;
+                    }
+                    break;
+            }
+            return false;
         }
 
         public void Close()
         {
-            Kernel32.CloseHandle(handle);
-            handle = IntPtr.Zero;
-        }
-
-        public void Flush()
-        {
-            if (handle == IntPtr.Zero)
-                throw new ObjectDisposedException("NamedPipeStream", "The stream has already been closed");
-            Kernel32.FlushFileBuffers(handle);
-        }
-
-        public bool Listen()
-        {
-            Disconnect();
-            if (Kernel32.ConnectNamedPipe(handle, IntPtr.Zero) != true)
-            {
-                uint lastErr = (uint)Marshal.GetLastWin32Error();
-                if (lastErr == ERROR_PIPE_CONNECTED)
-                    return true;
-                return false;
+            if (ioStream != null)
+                ioStream.Close();
+        }
+
+        public void WriteLoop()
+        {
+            try
+            {
+                while (true)
+                {
+                    if (cmdList.Count > 0)
+                    {
+                        byte[] wBuf = new byte[cmdList[0].Length];
+                        UTF8Encoding.UTF8.GetBytes(cmdList[0], 0, cmdList[0].Length, wBuf, 0);
+
+                        ioStream.Write(wBuf, 0, cmdList[0].Length);
+
+                        /* remove written data from commandlist */
+                        cmdList.RemoveAt(0);
+                    }
+                    else if (cmdList.Count == 0)
+                    {
+                        /* wait until new data is signaled */
+                        newWriteData.Reset();
+                        newWriteData.WaitOne();
+                    }
+                }
+            }
+            catch (Exception e)
+            {
+                if (PipeErrorEvent != null)
+                    PipeErrorEvent.Invoke(this, new PipeErrorEventArgs(e.Message));
+            }
+
+        }
+
+        public void ReadLoop()
+        {
+            byte[] buf = new byte[PIPE_SIZE];
+            int read = 0;
+
+            try
+            {
+                while(true)
+                {
+                    read = ioStream.Read(buf, 0, PIPE_SIZE);
+                    if (read > 0)
+                    {
+                        if (PipeReceiveEvent != null)
+                            PipeReceiveEvent.Invoke(this, new PipeReceiveEventArgs(UTF8Encoding.UTF8.GetString(buf, 0, read)));
+                    }
+                    else
+                    {
+                        /* connecion closed */
+                        break;
+                    }
+                }
+            }
+            catch (Exception e)
+            {
+                if (PipeErrorEvent != null)
+                    PipeErrorEvent.Invoke(this, new PipeErrorEventArgs(e.Message));
+            }
+        }
+
+        public bool Write(string str)
+        {
+            /* only forward a complete line */
+            wCommand += str;
+
+            if (str[str.Length-1] == '\r')
+            {
+                cmdList.Add(wCommand);
+                wCommand = null;
+
+                /* wake up the write thread */
+                newWriteData.Set();
             }
             return true;
-        }
-
-        public int Read(byte[] buffer, int offset, int count)
-        {
-            if (buffer == null)
-                throw new ArgumentNullException("buffer", "The buffer to read into cannot be null");
-            if (buffer.Length < (offset + count))
-                throw new ArgumentException("Buffer is not large enough to hold requested data", "buffer");
-            if (offset < 0)
-                throw new ArgumentOutOfRangeException("offset", offset, "Offset cannot be negative");
-            if (count < 0)
-                throw new ArgumentOutOfRangeException("count", count, "Count cannot be negative");
-            if (handle == IntPtr.Zero)
-                throw new ObjectDisposedException("NamedPipeStream", "The stream has already been closed");
-
-            // first read the data into an internal buffer since ReadFile cannot read into a buf at
-            // a specified offset
-            uint read = 0;
-
-            byte[] buf = buffer;
-            if (offset != 0)
-            {
-                buf = new byte[count];
-            }
-            bool f = Kernel32.ReadFile(handle, buf, (uint)count, ref read, IntPtr.Zero);
-            if (!f)
-            {
-                throw new Win32Exception(Marshal.GetLastWin32Error(), "ReadFile failed");
-            }
-            if (offset != 0)
-            {
-                for (int x = 0; x < read; x++)
-                {
-                    buffer[offset + x] = buf[x];
-                }
-
-            }
-            return (int)read;
-        }
-
-        public void Write(byte[] buffer, int offset, int count)
-        {
-            if (buffer == null)
-                throw new ArgumentNullException("buffer", "The buffer to write into cannot be null");
-            if (buffer.Length < (offset + count))
-                throw new ArgumentException("Buffer does not contain amount of requested data", "buffer");
-            if (offset < 0)
-                throw new ArgumentOutOfRangeException("offset", offset, "Offset cannot be negative");
-            if (count < 0)
-                throw new ArgumentOutOfRangeException("count", count, "Count cannot be negative");
-            if (handle == IntPtr.Zero)
-                throw new ObjectDisposedException("NamedPipeStream", "The stream has already been closed");
-
-            // copy data to internal buffer to allow writing from a specified offset
-            if (offset != 0)
-            {
-                byte[] buf = new Byte[count];
-                for (int x = 0; x < count; x++)
-                {
-                    buf[x] = buffer[offset + x];
-                }
-                buffer = buf;
-            }
-            uint written = 0;
-            bool result = Kernel32.WriteFile(handle, buffer, (uint)count, ref written, IntPtr.Zero);
-
-            if (!result)
-            {
-                int err = (int)Marshal.GetLastWin32Error();
-                throw new Win32Exception(err, "Writing to the stream failed");
-            }
-            if (written < count)
-                throw new IOException("Unable to write entire buffer to stream");
         }
     }
 }

Modified: trunk/tools/reactosdbg/Pipe/serialpipe.cs
URL: http://svn.reactos.org/svn/reactos/trunk/tools/reactosdbg/Pipe/serialpipe.cs?rev=36737&r1=36736&r2=36737&view=diff
==============================================================================
--- trunk/tools/reactosdbg/Pipe/serialpipe.cs [iso-8859-1] (original)
+++ trunk/tools/reactosdbg/Pipe/serialpipe.cs [iso-8859-1] Sun Oct 12 16:55:50 2008
@@ -80,7 +80,7 @@
 
         public void SerialPortErrorReceived(object sender, SerialErrorReceivedEventArgs args)
         {
-            mSerialPort.Close();
+            /* port will be closed by debug connection */
             if (PipeErrorEvent != null)
                 PipeErrorEvent.Invoke(this, new PipeErrorEventArgs(args.EventType.ToString()));
         }




More information about the Ros-dev mailing list