Merge pull request #3262 from lindenlab/add_continuations_test
[mono.git] / mcs / class / System.Core / System.IO.Pipes / PipeWin32.cs
1 //
2 // PipeWin32.cs
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
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
29 #if !BOOTSTRAP_BASIC
30
31 using System;
32 using System.ComponentModel;
33 using System.IO;
34 using System.Linq;
35 using System.Runtime.InteropServices;
36 using System.Security.AccessControl;
37 using System.Security.Permissions;
38 using System.Security.Principal;
39 using System.Text;
40 using Microsoft.Win32;
41 using Microsoft.Win32.SafeHandles;
42
43 namespace System.IO.Pipes
44 {
45         static class Win32PipeError
46         {
47                 public static Exception GetException ()
48                 {
49                         return GetException (Marshal.GetLastWin32Error ());
50                 }
51                 
52                 public static Exception GetException (int errorCode)
53                 {
54                         switch (errorCode) {
55                         case 5: return new UnauthorizedAccessException ();
56                         default: return new Win32Exception (errorCode);
57                         }
58                 }
59         }
60         
61         abstract class Win32AnonymousPipe : IPipe
62         {
63                 protected Win32AnonymousPipe ()
64                 {
65                 }
66
67                 public abstract SafePipeHandle Handle { get; }
68
69                 public void WaitForPipeDrain ()
70                 {
71                         throw new NotImplementedException ();
72                 }
73         }
74
75         class Win32AnonymousPipeClient : Win32AnonymousPipe, IAnonymousPipeClient
76         {
77                 // AnonymousPipeClientStream owner;
78
79                 public Win32AnonymousPipeClient (AnonymousPipeClientStream owner, SafePipeHandle handle)
80                 {
81                         // this.owner = owner;
82
83                         this.handle = handle;
84                 }
85
86                 SafePipeHandle handle;
87
88                 public override SafePipeHandle Handle {
89                         get { return handle; }
90                 }
91         }
92
93         class Win32AnonymousPipeServer : Win32AnonymousPipe, IAnonymousPipeServer
94         {
95                 // AnonymousPipeServerStream owner;
96
97                 public unsafe Win32AnonymousPipeServer (AnonymousPipeServerStream owner, PipeDirection direction,
98                                                         HandleInheritability inheritability, int bufferSize,
99                                                         PipeSecurity pipeSecurity)
100                 {
101                         IntPtr r, w;
102                         
103                         byte[] securityDescriptor = null;
104                         if (pipeSecurity != null)
105                                 securityDescriptor = pipeSecurity.GetSecurityDescriptorBinaryForm ();
106                                 
107                         fixed (byte* securityDescriptorPtr = securityDescriptor) {
108                                 SecurityAttributes att = new SecurityAttributes (inheritability, (IntPtr)securityDescriptorPtr);
109                                 if (!Win32Marshal.CreatePipe (out r, out w, ref att, bufferSize))
110                                         throw Win32PipeError.GetException ();
111                         }
112
113                         var rh = new SafePipeHandle (r, true);
114                         var wh = new SafePipeHandle (w, true);
115
116                         if (direction == PipeDirection.Out) {
117                                 server_handle = wh;
118                                 client_handle = rh;
119                         } else {
120                                 server_handle = rh;
121                                 client_handle = wh;
122                         }
123                 }
124
125                 public Win32AnonymousPipeServer (AnonymousPipeServerStream owner, SafePipeHandle serverHandle, SafePipeHandle clientHandle)
126                 {
127                         // this.owner = owner;
128                         this.server_handle = serverHandle;
129                         this.client_handle = clientHandle;
130                 }
131
132                 SafePipeHandle server_handle, client_handle;
133
134                 public override SafePipeHandle Handle {
135                         get { return server_handle; }
136                 }
137
138                 public SafePipeHandle ClientHandle {
139                         get { return client_handle; }
140                 }
141
142                 public void DisposeLocalCopyOfClientHandle ()
143                 {
144                         throw new NotImplementedException ();
145                 }
146         }
147
148         abstract class Win32NamedPipe : IPipe
149         {
150                 string name_cache;
151
152                 public string Name {
153                         get {
154                                 if (name_cache != null)
155                                         return name_cache;
156
157                                 int s, c, m, t;
158                                 byte [] un = new byte [200];
159                                 while (true) {
160                                         if (!Win32Marshal.GetNamedPipeHandleState (Handle, out s, out c, out m, out t, un, un.Length))
161                                                 throw Win32PipeError.GetException ();
162
163                                         if (un [un.Length - 1] == 0)
164                                                 break;
165                                         un = new byte [un.Length * 10];
166                                 }
167                                 name_cache = Encoding.Default.GetString (un);
168                                 return name_cache;
169                         }
170                 }
171
172                 public abstract SafePipeHandle Handle { get; }
173
174                 public void WaitForPipeDrain ()
175                 {
176                         throw new NotImplementedException ();
177                 }
178         }
179
180         class Win32NamedPipeClient : Win32NamedPipe, INamedPipeClient
181         {
182                 NamedPipeClientStream owner;
183
184                 // .ctor with existing handle
185                 public Win32NamedPipeClient (NamedPipeClientStream owner, SafePipeHandle safePipeHandle)
186                 {
187                         this.handle = safePipeHandle;
188                         this.owner = owner;
189
190                         // FIXME: retrieve is_async from state?
191                 }
192
193                 // .ctor without handle - create new
194                 public Win32NamedPipeClient (NamedPipeClientStream owner, string serverName, string pipeName,
195                                              PipeAccessRights desiredAccessRights, PipeOptions options,
196                                              HandleInheritability inheritability)
197                 {
198                         name = String.Format ("\\\\{0}\\pipe\\{1}", serverName, pipeName);
199                         var att = new SecurityAttributes (inheritability, IntPtr.Zero);
200                         is_async = (options & PipeOptions.Asynchronous) != PipeOptions.None;
201
202                         opener = delegate {
203                                 var ret = Win32Marshal.CreateFile (name, desiredAccessRights, 0, ref att, 3, 0, IntPtr.Zero);
204                                 if (ret == new IntPtr (-1L))
205                                         throw Win32PipeError.GetException ();
206
207                                 return new SafePipeHandle (ret, true);
208                         };
209                         this.owner = owner;
210                 }
211
212                 Func<SafePipeHandle> opener;
213                 bool is_async;
214                 string name;
215                 SafePipeHandle handle;
216
217                 public override SafePipeHandle Handle {
218                         get { return handle; }
219                 }
220
221                 public bool IsAsync {
222                         get { return is_async; }
223                 }
224
225                 public void Connect ()
226                 {
227                         if (owner.IsConnected)
228                                 throw new InvalidOperationException ("The named pipe is already connected");
229
230                         handle = opener ();
231                 }
232
233                 public void Connect (int timeout)
234                 {
235                         if (owner.IsConnected)
236                                 throw new InvalidOperationException ("The named pipe is already connected");
237
238                         if (!Win32Marshal.WaitNamedPipe (name, timeout))
239                                 throw Win32PipeError.GetException ();
240                         Connect ();
241                 }
242
243                 public int NumberOfServerInstances {
244                         get {
245                                 int s, c, m, t;
246                                 byte [] un = null;
247                                 if (!Win32Marshal.GetNamedPipeHandleState (Handle, out s, out c, out m, out t, un, 0))
248                                         throw Win32PipeError.GetException ();
249                                 return c;
250                         }
251                 }
252         }
253
254         class Win32NamedPipeServer : Win32NamedPipe, INamedPipeServer
255         {
256                 //NamedPipeServerStream owner;
257
258                 // .ctor with existing handle
259                 public Win32NamedPipeServer (NamedPipeServerStream owner, SafePipeHandle safePipeHandle)
260                 {
261                         handle = safePipeHandle;
262                         //this.owner = owner;
263                 }
264
265                 // .ctor without handle - create new
266                 public unsafe Win32NamedPipeServer (NamedPipeServerStream owner, string pipeName, int maxNumberOfServerInstances,
267                                                     PipeTransmissionMode transmissionMode, PipeAccessRights rights,
268                                                     PipeOptions options, int inBufferSize, int outBufferSize,
269                                                     PipeSecurity pipeSecurity, HandleInheritability inheritability)
270                 {
271                         string name = String.Format ("\\\\.\\pipe\\{0}", pipeName);
272
273                         uint openMode;
274                         openMode = (uint)rights | (uint)options; // Enum values match Win32 flags exactly.
275                         
276                         int pipeMode = 0;
277                         if ((owner.TransmissionMode & PipeTransmissionMode.Message) != 0)
278                                 pipeMode |= 4;
279                         //if ((readTransmissionMode & PipeTransmissionMode.Message) != 0)
280                         //      pipeMode |= 2;
281                         if ((options & PipeOptions.Asynchronous) != 0)
282                                 pipeMode |= 1;
283
284                         byte[] securityDescriptor = null;
285                         if (pipeSecurity != null)
286                                 securityDescriptor = pipeSecurity.GetSecurityDescriptorBinaryForm ();
287                         
288                         fixed (byte* securityDescriptorPtr = securityDescriptor) {
289                                 // FIXME: is nDefaultTimeout = 0 ok?
290                                 var att = new SecurityAttributes (inheritability, (IntPtr)securityDescriptorPtr);
291                                 var ret = Win32Marshal.CreateNamedPipe (name, openMode, pipeMode, maxNumberOfServerInstances,
292                                                                         outBufferSize, inBufferSize, 0, ref att, IntPtr.Zero);
293                                 if (ret == new IntPtr (-1L))
294                                         throw Win32PipeError.GetException ();
295                                 handle = new SafePipeHandle (ret, true);
296                         }
297                 }
298
299                 SafePipeHandle handle;
300
301                 public override SafePipeHandle Handle {
302                         get { return handle; }
303                 }
304
305                 public void Disconnect ()
306                 {
307                         Win32Marshal.DisconnectNamedPipe (Handle);
308                 }
309
310                 public void WaitForConnection ()
311                 {
312                         if (!Win32Marshal.ConnectNamedPipe (Handle, IntPtr.Zero))
313                                 throw Win32PipeError.GetException ();
314                 }
315         }
316
317         [StructLayout (LayoutKind.Sequential)]
318         struct SecurityAttributes
319         {
320                 public readonly int Length;
321                 public readonly IntPtr SecurityDescriptor;
322                 public readonly bool Inheritable;
323
324                 public SecurityAttributes (HandleInheritability inheritability, IntPtr securityDescriptor)
325                 {
326                         Length = Marshal.SizeOf (typeof (SecurityAttributes));
327                         SecurityDescriptor = securityDescriptor;
328                         Inheritable = inheritability == HandleInheritability.Inheritable;
329                 }
330         }
331
332         static class Win32Marshal
333         {
334                 internal static bool IsWindows {
335                         get {
336                                 switch (Environment.OSVersion.Platform) {
337                                 case PlatformID.Win32S:
338                                 case PlatformID.Win32Windows:
339                                 case PlatformID.Win32NT:
340                                 case PlatformID.WinCE:
341                                         return true;
342                                 default:
343                                         return false;
344                                 }
345                         }
346                 }
347
348                 // http://msdn.microsoft.com/en-us/library/aa365152%28VS.85%29.aspx
349                 [DllImport ("kernel32", SetLastError=true)]
350                 internal static extern bool CreatePipe (out IntPtr readHandle, out IntPtr writeHandle,
351                                                         ref SecurityAttributes pipeAtts, int size);
352
353                 // http://msdn.microsoft.com/en-us/library/aa365150%28VS.85%29.aspx
354                 [DllImport ("kernel32", SetLastError=true)]
355                 internal static extern IntPtr CreateNamedPipe (string name, uint openMode, int pipeMode, int maxInstances,
356                                                                int outBufferSize, int inBufferSize, int defaultTimeout,
357                                                                ref SecurityAttributes securityAttributes, IntPtr atts);
358
359                 // http://msdn.microsoft.com/en-us/library/aa365146%28VS.85%29.aspx
360                 [DllImport ("kernel32", SetLastError=true)]
361                 internal static extern bool ConnectNamedPipe (SafePipeHandle handle, IntPtr overlapped);
362
363                 // http://msdn.microsoft.com/en-us/library/aa365166%28VS.85%29.aspx
364                 [DllImport ("kernel32", SetLastError=true)]
365                 internal static extern bool DisconnectNamedPipe (SafePipeHandle handle);
366
367                 // http://msdn.microsoft.com/en-us/library/aa365443%28VS.85%29.aspx
368                 [DllImport ("kernel32", SetLastError=true)]
369                 internal static extern bool GetNamedPipeHandleState (SafePipeHandle handle,
370                                                                      out int state, out int curInstances,
371                                                                      out int maxCollectionCount, out int collectDateTimeout,
372                                                                      byte [] userName, int maxUserNameSize);
373
374                 // http://msdn.microsoft.com/en-us/library/aa365800%28VS.85%29.aspx
375                 [DllImport ("kernel32", SetLastError=true)]
376                 internal static extern bool WaitNamedPipe (string name, int timeout);
377
378                 // http://msdn.microsoft.com/en-us/library/aa363858%28VS.85%29.aspx
379                 [DllImport ("kernel32", SetLastError=true)]
380                 internal static extern IntPtr CreateFile (string name, PipeAccessRights desiredAccess, FileShare fileShare,
381                                               ref SecurityAttributes atts, int creationDisposition, int flags, IntPtr templateHandle);
382
383         }
384 }
385
386 #endif