StephaneLenclud@394: using System;
StephaneLenclud@394: using Microsoft.Win32.SafeHandles;
StephaneLenclud@394: using System.Text;
StephaneLenclud@394: using System.Runtime.InteropServices;
StephaneLenclud@394: using System.Threading;
StephaneLenclud@394: using System.IO;
StephaneLenclud@394: using System.Diagnostics;
StephaneLenclud@394: 
StephaneLenclud@394: namespace SoundGraph
StephaneLenclud@394: {
StephaneLenclud@394:     public class Server
StephaneLenclud@394:     {
StephaneLenclud@395:         [Flags]
StephaneLenclud@395:         public enum EFileAccess : uint
StephaneLenclud@395:         {
StephaneLenclud@395:             //
StephaneLenclud@395:             // Standart Section
StephaneLenclud@395:             //
StephaneLenclud@395: 
StephaneLenclud@395:             AccessSystemSecurity = 0x1000000,   // AccessSystemAcl access type
StephaneLenclud@395:             MaximumAllowed = 0x2000000,     // MaximumAllowed access type
StephaneLenclud@395: 
StephaneLenclud@395:             Delete = 0x10000,
StephaneLenclud@395:             ReadControl = 0x20000,
StephaneLenclud@395:             WriteDAC = 0x40000,
StephaneLenclud@395:             WriteOwner = 0x80000,
StephaneLenclud@395:             Synchronize = 0x100000,
StephaneLenclud@395: 
StephaneLenclud@395:             StandardRightsRequired = 0xF0000,
StephaneLenclud@395:             StandardRightsRead = ReadControl,
StephaneLenclud@395:             StandardRightsWrite = ReadControl,
StephaneLenclud@395:             StandardRightsExecute = ReadControl,
StephaneLenclud@395:             StandardRightsAll = 0x1F0000,
StephaneLenclud@395:             SpecificRightsAll = 0xFFFF,
StephaneLenclud@395: 
StephaneLenclud@395:             FILE_READ_DATA = 0x0001,        // file & pipe
StephaneLenclud@395:             FILE_LIST_DIRECTORY = 0x0001,       // directory
StephaneLenclud@395:             FILE_WRITE_DATA = 0x0002,       // file & pipe
StephaneLenclud@395:             FILE_ADD_FILE = 0x0002,         // directory
StephaneLenclud@395:             FILE_APPEND_DATA = 0x0004,      // file
StephaneLenclud@395:             FILE_ADD_SUBDIRECTORY = 0x0004,     // directory
StephaneLenclud@395:             FILE_CREATE_PIPE_INSTANCE = 0x0004, // named pipe
StephaneLenclud@395:             FILE_READ_EA = 0x0008,          // file & directory
StephaneLenclud@395:             FILE_WRITE_EA = 0x0010,         // file & directory
StephaneLenclud@395:             FILE_EXECUTE = 0x0020,          // file
StephaneLenclud@395:             FILE_TRAVERSE = 0x0020,         // directory
StephaneLenclud@395:             FILE_DELETE_CHILD = 0x0040,     // directory
StephaneLenclud@395:             FILE_READ_ATTRIBUTES = 0x0080,      // all
StephaneLenclud@395:             FILE_WRITE_ATTRIBUTES = 0x0100,     // all
StephaneLenclud@395: 
StephaneLenclud@395:             //
StephaneLenclud@395:             // Generic Section
StephaneLenclud@395:             //
StephaneLenclud@395: 
StephaneLenclud@395:             GenericRead = 0x80000000,
StephaneLenclud@395:             GenericWrite = 0x40000000,
StephaneLenclud@395:             GenericExecute = 0x20000000,
StephaneLenclud@395:             GenericAll = 0x10000000,
StephaneLenclud@395: 
StephaneLenclud@395:             SPECIFIC_RIGHTS_ALL = 0x00FFFF,
StephaneLenclud@395:             FILE_ALL_ACCESS =
StephaneLenclud@395:             StandardRightsRequired |
StephaneLenclud@395:             Synchronize |
StephaneLenclud@395:             0x1FF,
StephaneLenclud@395: 
StephaneLenclud@395:             FILE_GENERIC_READ =
StephaneLenclud@395:             StandardRightsRead |
StephaneLenclud@395:             FILE_READ_DATA |
StephaneLenclud@395:             FILE_READ_ATTRIBUTES |
StephaneLenclud@395:             FILE_READ_EA |
StephaneLenclud@395:             Synchronize,
StephaneLenclud@395: 
StephaneLenclud@395:             FILE_GENERIC_WRITE =
StephaneLenclud@395:             StandardRightsWrite |
StephaneLenclud@395:             FILE_WRITE_DATA |
StephaneLenclud@395:             FILE_WRITE_ATTRIBUTES |
StephaneLenclud@395:             FILE_WRITE_EA |
StephaneLenclud@395:             FILE_APPEND_DATA |
StephaneLenclud@395:             Synchronize,
StephaneLenclud@395: 
StephaneLenclud@395:             FILE_GENERIC_EXECUTE =
StephaneLenclud@395:             StandardRightsExecute |
StephaneLenclud@395:               FILE_READ_ATTRIBUTES |
StephaneLenclud@395:               FILE_EXECUTE |
StephaneLenclud@395:               Synchronize
StephaneLenclud@395:         }
StephaneLenclud@395: 
StephaneLenclud@395:         [Flags]
StephaneLenclud@395:         public enum EFileShare : uint
StephaneLenclud@395:         {
StephaneLenclud@395:             /// <summary>
StephaneLenclud@395:             /// 
StephaneLenclud@395:             /// </summary>
StephaneLenclud@395:             None = 0x00000000,
StephaneLenclud@395:             /// <summary>
StephaneLenclud@395:             /// Enables subsequent open operations on an object to request read access. 
StephaneLenclud@395:             /// Otherwise, other processes cannot open the object if they request read access. 
StephaneLenclud@395:             /// If this flag is not specified, but the object has been opened for read access, the function fails.
StephaneLenclud@395:             /// </summary>
StephaneLenclud@395:             Read = 0x00000001,
StephaneLenclud@395:             /// <summary>
StephaneLenclud@395:             /// Enables subsequent open operations on an object to request write access. 
StephaneLenclud@395:             /// Otherwise, other processes cannot open the object if they request write access. 
StephaneLenclud@395:             /// If this flag is not specified, but the object has been opened for write access, the function fails.
StephaneLenclud@395:             /// </summary>
StephaneLenclud@395:             Write = 0x00000002,
StephaneLenclud@395:             /// <summary>
StephaneLenclud@395:             /// Enables subsequent open operations on an object to request delete access. 
StephaneLenclud@395:             /// Otherwise, other processes cannot open the object if they request delete access.
StephaneLenclud@395:             /// If this flag is not specified, but the object has been opened for delete access, the function fails.
StephaneLenclud@395:             /// </summary>
StephaneLenclud@395:             Delete = 0x00000004
StephaneLenclud@395:         }
StephaneLenclud@395: 
StephaneLenclud@395:         public enum ECreationDisposition : uint
StephaneLenclud@395:         {
StephaneLenclud@395:             /// <summary>
StephaneLenclud@395:             /// Creates a new file. The function fails if a specified file exists.
StephaneLenclud@395:             /// </summary>
StephaneLenclud@395:             New = 1,
StephaneLenclud@395:             /// <summary>
StephaneLenclud@395:             /// Creates a new file, always. 
StephaneLenclud@395:             /// If a file exists, the function overwrites the file, clears the existing attributes, combines the specified file attributes, 
StephaneLenclud@395:             /// and flags with FILE_ATTRIBUTE_ARCHIVE, but does not set the security descriptor that the SECURITY_ATTRIBUTES structure specifies.
StephaneLenclud@395:             /// </summary>
StephaneLenclud@395:             CreateAlways = 2,
StephaneLenclud@395:             /// <summary>
StephaneLenclud@395:             /// Opens a file. The function fails if the file does not exist. 
StephaneLenclud@395:             /// </summary>
StephaneLenclud@395:             OpenExisting = 3,
StephaneLenclud@395:             /// <summary>
StephaneLenclud@395:             /// Opens a file, always. 
StephaneLenclud@395:             /// If a file does not exist, the function creates a file as if dwCreationDisposition is CREATE_NEW.
StephaneLenclud@395:             /// </summary>
StephaneLenclud@395:             OpenAlways = 4,
StephaneLenclud@395:             /// <summary>
StephaneLenclud@395:             /// Opens a file and truncates it so that its size is 0 (zero) bytes. The function fails if the file does not exist.
StephaneLenclud@395:             /// The calling process must open the file with the GENERIC_WRITE access right. 
StephaneLenclud@395:             /// </summary>
StephaneLenclud@395:             TruncateExisting = 5
StephaneLenclud@395:         }
StephaneLenclud@395: 
StephaneLenclud@395:         [Flags]
StephaneLenclud@395:         public enum EFileAttributes : uint
StephaneLenclud@395:         {
StephaneLenclud@395:             None = 0x00000000,
StephaneLenclud@395:             Readonly = 0x00000001,
StephaneLenclud@395:             Hidden = 0x00000002,
StephaneLenclud@395:             System = 0x00000004,
StephaneLenclud@395:             Directory = 0x00000010,
StephaneLenclud@395:             Archive = 0x00000020,
StephaneLenclud@395:             Device = 0x00000040,
StephaneLenclud@395:             Normal = 0x00000080,
StephaneLenclud@395:             Temporary = 0x00000100,
StephaneLenclud@395:             SparseFile = 0x00000200,
StephaneLenclud@395:             ReparsePoint = 0x00000400,
StephaneLenclud@395:             Compressed = 0x00000800,
StephaneLenclud@395:             Offline = 0x00001000,
StephaneLenclud@395:             NotContentIndexed = 0x00002000,
StephaneLenclud@395:             Encrypted = 0x00004000,
StephaneLenclud@395:             Write_Through = 0x80000000,
StephaneLenclud@395:             Overlapped = 0x40000000,
StephaneLenclud@395:             NoBuffering = 0x20000000,
StephaneLenclud@395:             RandomAccess = 0x10000000,
StephaneLenclud@395:             SequentialScan = 0x08000000,
StephaneLenclud@395:             DeleteOnClose = 0x04000000,
StephaneLenclud@395:             BackupSemantics = 0x02000000,
StephaneLenclud@395:             PosixSemantics = 0x01000000,
StephaneLenclud@395:             OpenReparsePoint = 0x00200000,
StephaneLenclud@395:             OpenNoRecall = 0x00100000,
StephaneLenclud@395:             FirstPipeInstance = 0x00080000
StephaneLenclud@395:         }
StephaneLenclud@395: 
StephaneLenclud@394:         [DllImport("kernel32.dll", SetLastError = true)]
StephaneLenclud@394:         public static extern SafeFileHandle CreateNamedPipe(
StephaneLenclud@394:            String pipeName,
StephaneLenclud@394:            uint dwOpenMode,
StephaneLenclud@394:            uint dwPipeMode,
StephaneLenclud@394:            uint nMaxInstances,
StephaneLenclud@394:            uint nOutBufferSize,
StephaneLenclud@394:            uint nInBufferSize,
StephaneLenclud@394:            uint nDefaultTimeOut,
StephaneLenclud@394:            IntPtr lpSecurityAttributes);
StephaneLenclud@394: 
StephaneLenclud@394:         [DllImport("kernel32.dll", SetLastError = true)]
StephaneLenclud@394:         public static extern int ConnectNamedPipe(
StephaneLenclud@394:            SafeFileHandle hNamedPipe,
StephaneLenclud@394:            IntPtr lpOverlapped);
StephaneLenclud@394: 
StephaneLenclud@394:         [DllImport("kernel32.dll", SetLastError = true)]
StephaneLenclud@394:         public static extern int DisconnectNamedPipe(
StephaneLenclud@394:            SafeFileHandle hNamedPipe);
StephaneLenclud@394: 
StephaneLenclud@395:         [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
StephaneLenclud@395:         public static extern SafeFileHandle CreateFile(
StephaneLenclud@395:            string lpFileName,
StephaneLenclud@395:            EFileAccess dwDesiredAccess,
StephaneLenclud@395:            EFileShare dwShareMode,
StephaneLenclud@395:            IntPtr lpSecurityAttributes,
StephaneLenclud@395:            ECreationDisposition dwCreationDisposition,
StephaneLenclud@395:            EFileAttributes dwFlagsAndAttributes,
StephaneLenclud@395:            IntPtr hTemplateFile);
StephaneLenclud@395: 
StephaneLenclud@395:         //[DllImport("kernel32.dll", SetLastError = true)]
StephaneLenclud@395:         //static extern bool CloseHandle(IntPtr hHandle);
StephaneLenclud@395: 
StephaneLenclud@394:         public const uint PIPE_ACCESS_DUPLEX = (0x00000003);
StephaneLenclud@394:         public const uint FILE_FLAG_OVERLAPPED = (0x40000000);
StephaneLenclud@394:         public const uint PIPE_ACCESS_OUTBOUND = (0x00000002);
StephaneLenclud@394:         public const uint PIPE_ACCESS_INBOUND = (0x00000001);
StephaneLenclud@394:         public const uint PIPE_TYPE_BYTE = (0x00000000);
StephaneLenclud@394:         public const uint PIPE_UNLIMITED_INSTANCES = 255;
StephaneLenclud@394:           
StephaneLenclud@394:         
StephaneLenclud@394: 
StephaneLenclud@394: 
StephaneLenclud@394:         public const int BUFFER_SIZE = 256;
StephaneLenclud@394: 
StephaneLenclud@394:         //
StephaneLenclud@394:         public string iPipeNameOutbound;
StephaneLenclud@394:         SafeFileHandle iPipeOutbound;
StephaneLenclud@394:         public FileStream iStreamOutbound;
StephaneLenclud@394:         //
StephaneLenclud@394:         public string iPipeNameInbound;
StephaneLenclud@394:         Thread iThreadInbound;
StephaneLenclud@394:         SafeFileHandle iPipeInbound;
StephaneLenclud@394:         public FileStream iStreamInbound;
StephaneLenclud@394: 
StephaneLenclud@395:         private bool iQuit = false;
StephaneLenclud@395: 
StephaneLenclud@394: 
StephaneLenclud@394:         public Server(string aPipeNameOutbound, string aPipeNameInbound)
StephaneLenclud@394:         {
StephaneLenclud@394:             iPipeNameOutbound = aPipeNameOutbound;
StephaneLenclud@394:             iPipeNameInbound = aPipeNameInbound;
StephaneLenclud@394:         }
StephaneLenclud@394:        
StephaneLenclud@394:         /**
StephaneLenclud@394:          * Start our services.
StephaneLenclud@394:          */
StephaneLenclud@394:         public void Start()
StephaneLenclud@394:         {
StephaneLenclud@394:             //Start inbound thread to receive messages
StephaneLenclud@394:             this.iThreadInbound = new Thread(new ThreadStart(ThreadInbound));
StephaneLenclud@394:             this.iThreadInbound.Start();
StephaneLenclud@394:         }
StephaneLenclud@394: 
StephaneLenclud@394:         /**
StephaneLenclud@395:          * Stop our services.
StephaneLenclud@394:          */
StephaneLenclud@395:         public void Stop()
StephaneLenclud@394:         {
StephaneLenclud@395:             iQuit = true;
StephaneLenclud@395:         }
StephaneLenclud@394: 
StephaneLenclud@394: 
StephaneLenclud@394:         /**
StephaneLenclud@394:          * Inbound thread is receiving messages from our client
StephaneLenclud@394:          */
StephaneLenclud@394:         private void ThreadInbound()
StephaneLenclud@394:         {
StephaneLenclud@394: 
StephaneLenclud@395:             //Keep on trying to connect on our read pipe
StephaneLenclud@395:             while ((iPipeInbound == null || iPipeInbound.IsInvalid) && !iQuit)
StephaneLenclud@395:             {
StephaneLenclud@395:                 Trace.WriteLine("Trying to connect to inbound pipe...");
StephaneLenclud@395:                 iPipeInbound = CreateFile(iPipeNameInbound, EFileAccess.GenericRead, EFileShare.None, IntPtr.Zero, ECreationDisposition.OpenExisting, EFileAttributes.None, IntPtr.Zero);
StephaneLenclud@395:                 System.Threading.Thread.Sleep(1000);
StephaneLenclud@395:             }
StephaneLenclud@395:             
StephaneLenclud@394: 
StephaneLenclud@394:             //Client now connected create our inbound stream
StephaneLenclud@395:             if (iPipeInbound!=null && !iPipeInbound.IsInvalid)
StephaneLenclud@395:             {
StephaneLenclud@395:                 iStreamInbound = new FileStream(iPipeInbound, FileAccess.Read, BUFFER_SIZE, false);
StephaneLenclud@395:                 if (iStreamInbound.CanRead)
StephaneLenclud@395:                 {
StephaneLenclud@395:                     Trace.WriteLine("Inbound stream ready!");
StephaneLenclud@395:                 }
StephaneLenclud@395:             }
StephaneLenclud@394: 
StephaneLenclud@394: 
StephaneLenclud@395:             //Keep on trying to connect to our write pipe
StephaneLenclud@395:             while ((iPipeOutbound == null || iPipeOutbound.IsInvalid) && !iQuit)
StephaneLenclud@395:             {
StephaneLenclud@395:                 Trace.WriteLine("Trying to connect to outbound pipe...");
StephaneLenclud@395:                 iPipeOutbound = CreateFile(iPipeNameOutbound, EFileAccess.GenericWrite, EFileShare.None, IntPtr.Zero, ECreationDisposition.OpenExisting, EFileAttributes.None, IntPtr.Zero);
StephaneLenclud@395:                 System.Threading.Thread.Sleep(1000);
StephaneLenclud@395:             }
StephaneLenclud@395:             
StephaneLenclud@395: 
StephaneLenclud@395:             //Client now connected create our stream
StephaneLenclud@395:             if (iPipeOutbound!=null && !iPipeOutbound.IsInvalid)
StephaneLenclud@395:             {
StephaneLenclud@395:                 iStreamOutbound = new FileStream(iPipeOutbound, FileAccess.Write, BUFFER_SIZE, false);
StephaneLenclud@395: 
StephaneLenclud@395:                 if (iStreamOutbound.CanWrite)
StephaneLenclud@395:                 {
StephaneLenclud@395:                     Trace.WriteLine("Outbound stream ready!");
StephaneLenclud@395:                 }
StephaneLenclud@395:             }
StephaneLenclud@395: 
StephaneLenclud@395: 
StephaneLenclud@395:             //Listening loop
StephaneLenclud@394:             byte[] buffer = null;
StephaneLenclud@394:             ASCIIEncoding encoder = new ASCIIEncoding();
StephaneLenclud@394: 
StephaneLenclud@395:             while (!iQuit)
StephaneLenclud@394:             {                
StephaneLenclud@394:                 int bytesRead = 0;
StephaneLenclud@394: 
StephaneLenclud@394:                 try
StephaneLenclud@394:                 {
StephaneLenclud@394:                     buffer = new byte[BUFFER_SIZE];
StephaneLenclud@394:                     bytesRead = iStreamInbound.Read(buffer, 0, BUFFER_SIZE);
StephaneLenclud@394:                 }
StephaneLenclud@394:                 catch
StephaneLenclud@394:                 {
StephaneLenclud@394:                     //read error has occurred
StephaneLenclud@394:                     break;
StephaneLenclud@394:                 }
StephaneLenclud@394: 
StephaneLenclud@394:                 //client has disconnected
StephaneLenclud@394:                 if (bytesRead == 0)
StephaneLenclud@394:                     break;
StephaneLenclud@394: 
StephaneLenclud@394:                 //fire message received event
StephaneLenclud@394:                 //if (this.MessageReceived != null)
StephaneLenclud@394:                 //    this.MessageReceived(clientse, encoder.GetString(buffer, 0, bytesRead));
StephaneLenclud@394: 
StephaneLenclud@394:                 int ReadLength = 0;
StephaneLenclud@394:                 for (int i = 0; i < BUFFER_SIZE; i++)
StephaneLenclud@394:                 {
StephaneLenclud@394:                     //if (buffer[i].ToString("x2") != "cc")
StephaneLenclud@394:                     if (buffer[i] != 0)
StephaneLenclud@394:                     {
StephaneLenclud@394:                         ReadLength++;
StephaneLenclud@394:                     }
StephaneLenclud@394:                     else
StephaneLenclud@394:                         break;
StephaneLenclud@394:                 }
StephaneLenclud@394:                 if (ReadLength > 0)
StephaneLenclud@394:                 {
StephaneLenclud@394:                     byte[] Rc = new byte[ReadLength];
StephaneLenclud@394:                     Buffer.BlockCopy(buffer, 0, Rc, 0, ReadLength);
StephaneLenclud@394: 
StephaneLenclud@395:                     Trace.WriteLine(encoder.GetString(Rc, 0, ReadLength));
StephaneLenclud@394:                     Trace.WriteLine("Received " + ReadLength + " Bytes: " + encoder.GetString(Rc, 0, ReadLength));
StephaneLenclud@394:                     buffer.Initialize();
StephaneLenclud@394:                 }
StephaneLenclud@394:                
StephaneLenclud@394:             }
StephaneLenclud@394: 
StephaneLenclud@395:  
StephaneLenclud@394:             //clean up resources
StephaneLenclud@395:             if (iStreamInbound!=null) iStreamInbound.Close();
StephaneLenclud@395:             if (iPipeInbound != null) iPipeInbound.Close();
StephaneLenclud@395:             //
StephaneLenclud@395:             if (iStreamOutbound != null) iStreamOutbound.Close();
StephaneLenclud@395:             if (iPipeOutbound != null) iPipeOutbound.Close();
StephaneLenclud@394:         }
StephaneLenclud@394: 
StephaneLenclud@394:         /**
StephaneLenclud@394:          * Send a message to our client.
StephaneLenclud@394:          */
StephaneLenclud@394:         public void SendMessage(string message)
StephaneLenclud@394:         {
StephaneLenclud@397:             byte[] m8 = new byte[message.Length];
StephaneLenclud@397:             int i = 0;
StephaneLenclud@397:             foreach (char c in message)
StephaneLenclud@397:             {
StephaneLenclud@397:                 m8[i]=System.Convert.ToByte(c);
StephaneLenclud@397:                 i++;
StephaneLenclud@397:             }
StephaneLenclud@394: 
StephaneLenclud@397:             //ASCIIEncoding encoder = new ASCIIEncoding();
StephaneLenclud@397:             //byte[] messageBuffer = encoder.GetBytes(message);
StephaneLenclud@394: 
StephaneLenclud@397:             if (iStreamOutbound != null && iStreamOutbound.CanWrite)
StephaneLenclud@397:             {
StephaneLenclud@397:                 //iStreamOutbound.Write(messageBuffer, 0, messageBuffer.Length);
StephaneLenclud@397:                 iStreamOutbound.Write(m8, 0, message.Length);
StephaneLenclud@397:                 iStreamOutbound.Flush();
StephaneLenclud@397:             }
StephaneLenclud@394: 
StephaneLenclud@394: 
StephaneLenclud@394:         }
StephaneLenclud@394: 
StephaneLenclud@394: 
StephaneLenclud@394:     }
StephaneLenclud@394: }