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 	{
GetException()47 		public static Exception GetException ()
48 		{
49 			return GetException (Marshal.GetLastWin32Error ());
50 		}
51 
GetException(int errorCode)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 	{
Win32AnonymousPipe()63 		protected Win32AnonymousPipe ()
64 		{
65 		}
66 
67 		public abstract SafePipeHandle Handle { get; }
68 
WaitForPipeDrain()69 		public void WaitForPipeDrain ()
70 		{
71 			throw new NotImplementedException ();
72 		}
73 	}
74 
75 	class Win32AnonymousPipeClient : Win32AnonymousPipe, IAnonymousPipeClient
76 	{
77 		// AnonymousPipeClientStream owner;
78 
Win32AnonymousPipeClient(AnonymousPipeClientStream owner, SafePipeHandle handle)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 
Win32AnonymousPipeServer(AnonymousPipeServerStream owner, PipeDirection direction, HandleInheritability inheritability, int bufferSize, PipeSecurity pipeSecurity)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 
Win32AnonymousPipeServer(AnonymousPipeServerStream owner, SafePipeHandle serverHandle, SafePipeHandle clientHandle)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 
DisposeLocalCopyOfClientHandle()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 
WaitForPipeDrain()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
Win32NamedPipeClient(NamedPipeClientStream owner, SafePipeHandle safePipeHandle)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
Win32NamedPipeClient(NamedPipeClientStream owner, string serverName, string pipeName, PipeAccessRights desiredAccessRights, PipeOptions options, HandleInheritability inheritability)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 
Connect()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 
Connect(int timeout)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
Win32NamedPipeServer(NamedPipeServerStream owner, SafePipeHandle safePipeHandle)259 		public Win32NamedPipeServer (NamedPipeServerStream owner, SafePipeHandle safePipeHandle)
260 		{
261 			handle = safePipeHandle;
262 			//this.owner = owner;
263 		}
264 
265 		// .ctor without handle - create new
Win32NamedPipeServer(NamedPipeServerStream owner, string pipeName, int maxNumberOfServerInstances, PipeTransmissionMode transmissionMode, PipeAccessRights rights, PipeOptions options, int inBufferSize, int outBufferSize, PipeSecurity pipeSecurity, HandleInheritability inheritability)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 
Disconnect()305 		public void Disconnect ()
306 		{
307 			Win32Marshal.DisconnectNamedPipe (Handle);
308 		}
309 
WaitForConnection()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 
SecurityAttributesSystem.IO.Pipes.SecurityAttributes324 		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)]
CreatePipe(out IntPtr readHandle, out IntPtr writeHandle, ref SecurityAttributes pipeAtts, int size)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)]
CreateNamedPipe(string name, uint openMode, int pipeMode, int maxInstances, int outBufferSize, int inBufferSize, int defaultTimeout, ref SecurityAttributes securityAttributes, IntPtr atts)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)]
ConnectNamedPipe(SafePipeHandle handle, IntPtr overlapped)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)]
DisconnectNamedPipe(SafePipeHandle handle)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)]
GetNamedPipeHandleState(SafePipeHandle handle, out int state, out int curInstances, out int maxCollectionCount, out int collectDateTimeout, byte [] userName, int maxUserNameSize)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)]
WaitNamedPipe(string name, int timeout)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)]
CreateFile(string name, PipeAccessRights desiredAccess, FileShare fileShare, ref SecurityAttributes atts, int creationDisposition, int flags, IntPtr templateHandle)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
387