PipeWin32.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. //
  2. // PipeWin32.cs
  3. //
  4. // Author:
  5. // Atsushi Enomoto <[email protected]>
  6. //
  7. // Copyright (C) 2009 Novell, Inc. http://www.novell.com
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. #if !BOOTSTRAP_BASIC
  29. using System;
  30. using System.ComponentModel;
  31. using System.IO;
  32. using System.Linq;
  33. using System.Runtime.InteropServices;
  34. using System.Security.AccessControl;
  35. using System.Security.Permissions;
  36. using System.Security.Principal;
  37. using System.Text;
  38. using Microsoft.Win32;
  39. using Microsoft.Win32.SafeHandles;
  40. namespace System.IO.Pipes
  41. {
  42. static class Win32PipeError
  43. {
  44. public static Exception GetException ()
  45. {
  46. return GetException (Marshal.GetLastWin32Error ());
  47. }
  48. public static Exception GetException (int errorCode)
  49. {
  50. switch (errorCode) {
  51. case 5: return new UnauthorizedAccessException ();
  52. default: return new Win32Exception (errorCode);
  53. }
  54. }
  55. }
  56. abstract class Win32AnonymousPipe : IPipe
  57. {
  58. protected Win32AnonymousPipe ()
  59. {
  60. }
  61. public abstract SafePipeHandle Handle { get; }
  62. public void WaitForPipeDrain ()
  63. {
  64. throw new NotImplementedException ();
  65. }
  66. }
  67. class Win32AnonymousPipeClient : Win32AnonymousPipe, IAnonymousPipeClient
  68. {
  69. // AnonymousPipeClientStream owner;
  70. public Win32AnonymousPipeClient (AnonymousPipeClientStream owner, SafePipeHandle handle)
  71. {
  72. // this.owner = owner;
  73. this.handle = handle;
  74. }
  75. SafePipeHandle handle;
  76. public override SafePipeHandle Handle {
  77. get { return handle; }
  78. }
  79. }
  80. class Win32AnonymousPipeServer : Win32AnonymousPipe, IAnonymousPipeServer
  81. {
  82. // AnonymousPipeServerStream owner;
  83. public unsafe Win32AnonymousPipeServer (AnonymousPipeServerStream owner, PipeDirection direction,
  84. HandleInheritability inheritability, int bufferSize,
  85. PipeSecurity pipeSecurity)
  86. {
  87. IntPtr r, w;
  88. byte[] securityDescriptor = null;
  89. if (pipeSecurity != null)
  90. securityDescriptor = pipeSecurity.GetSecurityDescriptorBinaryForm ();
  91. fixed (byte* securityDescriptorPtr = securityDescriptor) {
  92. SecurityAttributes att = new SecurityAttributes (inheritability, (IntPtr)securityDescriptorPtr);
  93. if (!Win32Marshal.CreatePipe (out r, out w, ref att, bufferSize))
  94. throw Win32PipeError.GetException ();
  95. }
  96. var rh = new SafePipeHandle (r, true);
  97. var wh = new SafePipeHandle (w, true);
  98. if (direction == PipeDirection.Out) {
  99. server_handle = wh;
  100. client_handle = rh;
  101. } else {
  102. server_handle = rh;
  103. client_handle = wh;
  104. }
  105. }
  106. public Win32AnonymousPipeServer (AnonymousPipeServerStream owner, SafePipeHandle serverHandle, SafePipeHandle clientHandle)
  107. {
  108. // this.owner = owner;
  109. this.server_handle = serverHandle;
  110. this.client_handle = clientHandle;
  111. }
  112. SafePipeHandle server_handle, client_handle;
  113. public override SafePipeHandle Handle {
  114. get { return server_handle; }
  115. }
  116. public SafePipeHandle ClientHandle {
  117. get { return client_handle; }
  118. }
  119. public void DisposeLocalCopyOfClientHandle ()
  120. {
  121. throw new NotImplementedException ();
  122. }
  123. }
  124. abstract class Win32NamedPipe : IPipe
  125. {
  126. string name_cache;
  127. public string Name {
  128. get {
  129. if (name_cache != null)
  130. return name_cache;
  131. int s, c, m, t;
  132. byte [] un = new byte [200];
  133. while (true) {
  134. if (!Win32Marshal.GetNamedPipeHandleState (Handle, out s, out c, out m, out t, un, un.Length))
  135. throw Win32PipeError.GetException ();
  136. if (un [un.Length - 1] == 0)
  137. break;
  138. un = new byte [un.Length * 10];
  139. }
  140. name_cache = Encoding.Default.GetString (un);
  141. return name_cache;
  142. }
  143. }
  144. public abstract SafePipeHandle Handle { get; }
  145. public void WaitForPipeDrain ()
  146. {
  147. throw new NotImplementedException ();
  148. }
  149. }
  150. class Win32NamedPipeClient : Win32NamedPipe, INamedPipeClient
  151. {
  152. NamedPipeClientStream owner;
  153. // .ctor with existing handle
  154. public Win32NamedPipeClient (NamedPipeClientStream owner, SafePipeHandle safePipeHandle)
  155. {
  156. this.handle = safePipeHandle;
  157. this.owner = owner;
  158. // FIXME: retrieve is_async from state?
  159. }
  160. // .ctor without handle - create new
  161. public Win32NamedPipeClient (NamedPipeClientStream owner, string serverName, string pipeName,
  162. PipeAccessRights desiredAccessRights, PipeOptions options,
  163. HandleInheritability inheritability)
  164. {
  165. name = String.Format ("\\\\{0}\\pipe\\{1}", serverName, pipeName);
  166. var att = new SecurityAttributes (inheritability, IntPtr.Zero);
  167. is_async = (options & PipeOptions.Asynchronous) != PipeOptions.None;
  168. opener = delegate {
  169. var ret = Win32Marshal.CreateFile (name, desiredAccessRights, 0, ref att, 3, 0, IntPtr.Zero);
  170. if (ret == new IntPtr (-1L))
  171. throw Win32PipeError.GetException ();
  172. return new SafePipeHandle (ret, true);
  173. };
  174. this.owner = owner;
  175. }
  176. Func<SafePipeHandle> opener;
  177. bool is_async;
  178. string name;
  179. SafePipeHandle handle;
  180. public override SafePipeHandle Handle {
  181. get { return handle; }
  182. }
  183. public bool IsAsync {
  184. get { return is_async; }
  185. }
  186. public void Connect ()
  187. {
  188. if (owner.IsConnected)
  189. throw new InvalidOperationException ("The named pipe is already connected");
  190. handle = opener ();
  191. }
  192. public void Connect (int timeout)
  193. {
  194. if (owner.IsConnected)
  195. throw new InvalidOperationException ("The named pipe is already connected");
  196. if (!Win32Marshal.WaitNamedPipe (name, timeout))
  197. throw Win32PipeError.GetException ();
  198. Connect ();
  199. }
  200. public int NumberOfServerInstances {
  201. get {
  202. int s, c, m, t;
  203. byte [] un = null;
  204. if (!Win32Marshal.GetNamedPipeHandleState (Handle, out s, out c, out m, out t, un, 0))
  205. throw Win32PipeError.GetException ();
  206. return c;
  207. }
  208. }
  209. }
  210. class Win32NamedPipeServer : Win32NamedPipe, INamedPipeServer
  211. {
  212. //NamedPipeServerStream owner;
  213. // .ctor with existing handle
  214. public Win32NamedPipeServer (NamedPipeServerStream owner, SafePipeHandle safePipeHandle)
  215. {
  216. handle = safePipeHandle;
  217. //this.owner = owner;
  218. }
  219. // .ctor without handle - create new
  220. public unsafe Win32NamedPipeServer (NamedPipeServerStream owner, string pipeName, int maxNumberOfServerInstances,
  221. PipeTransmissionMode transmissionMode, PipeAccessRights rights,
  222. PipeOptions options, int inBufferSize, int outBufferSize,
  223. PipeSecurity pipeSecurity, HandleInheritability inheritability)
  224. {
  225. string name = String.Format ("\\\\.\\pipe\\{0}", pipeName);
  226. uint openMode;
  227. openMode = (uint)rights | (uint)options; // Enum values match Win32 flags exactly.
  228. int pipeMode = 0;
  229. if ((owner.TransmissionMode & PipeTransmissionMode.Message) != 0)
  230. pipeMode |= 4;
  231. //if ((readTransmissionMode & PipeTransmissionMode.Message) != 0)
  232. // pipeMode |= 2;
  233. if ((options & PipeOptions.Asynchronous) != 0)
  234. pipeMode |= 1;
  235. byte[] securityDescriptor = null;
  236. if (pipeSecurity != null)
  237. securityDescriptor = pipeSecurity.GetSecurityDescriptorBinaryForm ();
  238. fixed (byte* securityDescriptorPtr = securityDescriptor) {
  239. // FIXME: is nDefaultTimeout = 0 ok?
  240. var att = new SecurityAttributes (inheritability, (IntPtr)securityDescriptorPtr);
  241. var ret = Win32Marshal.CreateNamedPipe (name, openMode, pipeMode, maxNumberOfServerInstances,
  242. outBufferSize, inBufferSize, 0, ref att, IntPtr.Zero);
  243. if (ret == new IntPtr (-1L))
  244. throw Win32PipeError.GetException ();
  245. handle = new SafePipeHandle (ret, true);
  246. }
  247. }
  248. SafePipeHandle handle;
  249. public override SafePipeHandle Handle {
  250. get { return handle; }
  251. }
  252. public void Disconnect ()
  253. {
  254. Win32Marshal.DisconnectNamedPipe (Handle);
  255. }
  256. public void WaitForConnection ()
  257. {
  258. if (!Win32Marshal.ConnectNamedPipe (Handle, IntPtr.Zero))
  259. throw Win32PipeError.GetException ();
  260. }
  261. }
  262. [StructLayout (LayoutKind.Sequential)]
  263. struct SecurityAttributes
  264. {
  265. public readonly int Length;
  266. public readonly IntPtr SecurityDescriptor;
  267. public readonly bool Inheritable;
  268. public SecurityAttributes (HandleInheritability inheritability, IntPtr securityDescriptor)
  269. {
  270. Length = Marshal.SizeOf (typeof (SecurityAttributes));
  271. SecurityDescriptor = securityDescriptor;
  272. Inheritable = inheritability == HandleInheritability.Inheritable;
  273. }
  274. }
  275. static class Win32Marshal
  276. {
  277. internal static bool IsWindows {
  278. get {
  279. switch (Environment.OSVersion.Platform) {
  280. case PlatformID.Win32S:
  281. case PlatformID.Win32Windows:
  282. case PlatformID.Win32NT:
  283. case PlatformID.WinCE:
  284. return true;
  285. default:
  286. return false;
  287. }
  288. }
  289. }
  290. // http://msdn.microsoft.com/en-us/library/aa365152%28VS.85%29.aspx
  291. [DllImport ("kernel32", SetLastError=true)]
  292. internal static extern bool CreatePipe (out IntPtr readHandle, out IntPtr writeHandle,
  293. ref SecurityAttributes pipeAtts, int size);
  294. // http://msdn.microsoft.com/en-us/library/aa365150%28VS.85%29.aspx
  295. [DllImport ("kernel32", SetLastError=true)]
  296. internal static extern IntPtr CreateNamedPipe (string name, uint openMode, int pipeMode, int maxInstances,
  297. int outBufferSize, int inBufferSize, int defaultTimeout,
  298. ref SecurityAttributes securityAttributes, IntPtr atts);
  299. // http://msdn.microsoft.com/en-us/library/aa365146%28VS.85%29.aspx
  300. [DllImport ("kernel32", SetLastError=true)]
  301. internal static extern bool ConnectNamedPipe (SafePipeHandle handle, IntPtr overlapped);
  302. // http://msdn.microsoft.com/en-us/library/aa365166%28VS.85%29.aspx
  303. [DllImport ("kernel32", SetLastError=true)]
  304. internal static extern bool DisconnectNamedPipe (SafePipeHandle handle);
  305. // http://msdn.microsoft.com/en-us/library/aa365443%28VS.85%29.aspx
  306. [DllImport ("kernel32", SetLastError=true)]
  307. internal static extern bool GetNamedPipeHandleState (SafePipeHandle handle,
  308. out int state, out int curInstances,
  309. out int maxCollectionCount, out int collectDateTimeout,
  310. byte [] userName, int maxUserNameSize);
  311. // http://msdn.microsoft.com/en-us/library/aa365800%28VS.85%29.aspx
  312. [DllImport ("kernel32", SetLastError=true)]
  313. internal static extern bool WaitNamedPipe (string name, int timeout);
  314. // http://msdn.microsoft.com/en-us/library/aa363858%28VS.85%29.aspx
  315. [DllImport ("kernel32", SetLastError=true)]
  316. internal static extern IntPtr CreateFile (string name, PipeAccessRights desiredAccess, FileShare fileShare,
  317. ref SecurityAttributes atts, int creationDisposition, int flags, IntPtr templateHandle);
  318. }
  319. }
  320. #endif