New test.
[mono.git] / mcs / class / System.Runtime.Remoting / System.Runtime.Remoting.Channels.Ipc.Win32 / NamedPipeSocket.cs
1 //
2 // System.Runtime.Remoting.Channels.Ipc.Win32.NamedPipeSocket.cs
3 //
4 // Author: Robert Jordan (robertj@gmx.net)
5 //
6 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
7 //
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 NET_2_0
30
31 using System;
32 using System.IO;
33 using System.Runtime.InteropServices;
34 using System.Runtime.Remoting.Messaging;
35 using System.Text;
36
37 namespace System.Runtime.Remoting.Channels.Ipc.Win32
38 {
39     /// <summary>
40     /// Implements a local Named Pipe socket.
41     /// </summary>
42     internal class NamedPipeSocket : IDisposable
43     {
44         IntPtr hPipe;
45
46         /// <summary>
47         /// Creates a new socket instance form the specified local Named Pipe handle.
48         /// </summary>
49         /// <param name="hPipe">The handle.</param>
50         internal NamedPipeSocket(IntPtr hPipe)
51         {
52             this.hPipe = hPipe;
53             this.info = new NamedPipeSocketInfo(hPipe);
54         }
55
56         ~NamedPipeSocket() 
57         {
58             ((IDisposable)this).Dispose();
59         }
60
61         /// <summary>
62         /// Gets the NamedPipeSocketInfo of this instance.
63         /// </summary>
64         /// <returns></returns>
65         public NamedPipeSocketInfo Info
66         {
67             get 
68             {
69                 return info;
70             }
71         }
72
73         NamedPipeSocketInfo info;
74
75         /// <summary>
76         /// Closes the socket.
77         /// </summary>
78         public void Close() 
79         {
80             ((IDisposable)this).Dispose();
81         }
82
83         /// <summary>
84         /// Disposes the object.
85         /// </summary>
86         void IDisposable.Dispose()
87         {
88             if (hPipe != IntPtr.Zero) 
89             {
90                 try 
91                 {
92                     // disconnect the pipe
93                     if (Info.IsServer) 
94                     {
95                         NamedPipeHelper.FlushFileBuffers(hPipe);
96                         NamedPipeHelper.DisconnectNamedPipe(hPipe);
97                     }
98                 }
99                 catch (NamedPipeException) 
100                 {
101                 }
102
103                 NamedPipeHelper.CloseHandle(hPipe);
104                 hPipe = IntPtr.Zero;
105                 GC.SuppressFinalize(this);
106             }
107         }
108
109         /// <summary>
110         /// Returns the stream used to send and receive data.
111         /// </summary>
112         /// <returns></returns>
113         public Stream GetStream() 
114         {
115             if (hPipe == IntPtr.Zero)
116                 throw new ObjectDisposedException(GetType().FullName);
117
118             return stream == null
119                 ? stream = new NamedPipeStream(this, false)
120                 : stream;
121         }
122
123         Stream stream;
124
125         /// <summary>
126         /// Returns the stream used to send and receive data. The stream disposes
127         /// the socket on close.
128         /// </summary>
129         /// <returns></returns>
130         public Stream GetClosingStream() 
131         {
132             if (hPipe == IntPtr.Zero)
133                 throw new ObjectDisposedException(GetType().FullName);
134             
135             return new NamedPipeStream(this, true);
136         }
137
138         /// <summary>
139         /// Flushes the socket.
140         /// </summary>
141         public void Flush() 
142         {
143             if (hPipe == IntPtr.Zero)
144                 throw new ObjectDisposedException(GetType().FullName);
145
146             NamedPipeHelper.FlushFileBuffers(hPipe);
147         }
148
149         /// <summary>
150         /// Receives the specified number of bytes from a socket into
151         /// the specified offset position of the receive buffer.
152         /// </summary>
153         /// <param name="buffer">An array of type Byte that is the storage
154         /// location for received data.</param>
155         /// <param name="offset">The location in buffer to store the received data.</param>
156         /// <param name="count">The number of bytes to receive.</param>
157         /// <returns>The number of bytes received.</returns>
158         public int Receive(byte[] buffer, int offset, int count) 
159         {
160             if (hPipe == IntPtr.Zero)
161                 throw new ObjectDisposedException(GetType().FullName);
162             if (buffer == null)
163                 throw new ArgumentNullException("buffer");
164             if (offset < 0 || count < 0)
165                 throw new ArgumentOutOfRangeException("offset and/or count");
166             if (buffer.Length - offset < count)
167                 throw new ArgumentException();
168
169             uint read = 0;
170
171             GCHandle gch  = GCHandle.Alloc(buffer, GCHandleType.Pinned);
172             try 
173             {
174                 bool res = NamedPipeHelper.ReadFile(
175                     hPipe,
176                     Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset),
177                     (uint) count,
178                     out read,
179                     IntPtr.Zero
180                     );
181
182                 if (!res && read == 0) throw new NamedPipeException();
183
184                 return (int) read;
185             }
186             finally 
187             {
188                 gch.Free();
189             }
190         }
191
192         delegate int ReceiveMethod(byte[] buffer, int offset, int count);
193
194         public IAsyncResult BeginReceive(byte[] buffer, int offset, int count,
195             AsyncCallback callback, object state)
196         {
197             return new ReceiveMethod(Receive).BeginInvoke(buffer, offset, count, callback, state);
198         }
199
200         public int EndReceive(IAsyncResult asyncResult) 
201         {
202             AsyncResult ar = asyncResult as AsyncResult;
203             return ((ReceiveMethod)ar.AsyncDelegate).EndInvoke(asyncResult);
204         }
205
206         /// <summary>
207         /// Sends the specified number of bytes of data to a connected socket,
208         /// starting at the specified offset.
209         /// </summary>
210         /// <param name="buffer">An array of type Byte that contains the data to be sent.</param>
211         /// <param name="offset">The position in the data buffer at which to begin sending data. </param>
212         /// <param name="count">The number of bytes to send.</param>
213         /// <returns>The number of bytes sent.</returns>
214         public int Send(byte[] buffer, int offset, int count) 
215         {
216             if (hPipe == IntPtr.Zero)
217                 throw new ObjectDisposedException(GetType().FullName);
218             if (buffer == null)
219                 throw new ArgumentNullException("buffer");
220             if (offset < 0 || count < 0)
221                 throw new ArgumentOutOfRangeException("offset and/or count");
222             if (buffer.Length - offset < count)
223                 throw new ArgumentException();
224
225             uint written = 0;
226
227             GCHandle gch  = GCHandle.Alloc(buffer, GCHandleType.Pinned);
228             try 
229             {
230                 bool res = NamedPipeHelper.WriteFile(
231                     hPipe,
232                     Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset),
233                     (uint) count,
234                     out written,
235                     IntPtr.Zero
236                     );
237
238                 if (!res) throw new NamedPipeException();
239                 return (int) written;
240             }
241             finally 
242             {
243                 gch.Free();
244             }
245         }
246
247         delegate int SendMethod(byte[] buffer, int offset, int count);
248
249         public IAsyncResult BeginSend(byte[] buffer, int offset, int count,
250             AsyncCallback callback, object state)
251         {
252             return new SendMethod(Send).BeginInvoke(buffer, offset, count, callback, state);
253         }
254
255         public int EndSend(IAsyncResult asyncResult) 
256         {
257             AsyncResult ar = asyncResult as AsyncResult;
258             return ((SendMethod)ar.AsyncDelegate).EndInvoke(asyncResult);
259         }
260
261         /// <summary>
262         /// Returns the current NamedPipeSocketState of this instance.
263         /// </summary>
264         /// <returns></returns>
265         public NamedPipeSocketState GetSocketState() 
266         {
267             if (hPipe == IntPtr.Zero)
268                 throw new ObjectDisposedException(GetType().FullName);
269
270             return new NamedPipeSocketState(hPipe);
271         }
272
273         /// <summary>
274         /// Impersonates the client.
275         /// </summary>
276         public void Impersonate() 
277         {
278             if (hPipe == IntPtr.Zero)
279                 throw new ObjectDisposedException(GetType().FullName);
280
281             if (Info.IsServer)
282                 if (!NamedPipeHelper.ImpersonateNamedPipeClient(hPipe))
283                     throw new NamedPipeException();
284         }
285
286         /// <summary>
287         /// Reverts the impersonation.
288         /// </summary>
289         public static bool RevertToSelf() 
290         {
291             return NamedPipeHelper.RevertToSelf();
292         }
293
294     }
295
296
297     /// <summary>
298     /// Represents local Named Pipe informations.
299     /// </summary>
300     internal class NamedPipeSocketInfo
301     {
302         public readonly int Flags;
303         public readonly int OutBufferSize;
304         public readonly int InBufferSize;
305         public readonly int MaxInstances;
306
307         public bool IsServer 
308         {
309             get 
310             {
311                 return (Flags & NamedPipeHelper.PIPE_SERVER_END) != 0;
312             }
313         }
314
315         internal NamedPipeSocketInfo(IntPtr hPipe) 
316         {
317             bool res = NamedPipeHelper.GetNamedPipeInfo(
318                 hPipe,
319                 out Flags,
320                 out OutBufferSize,
321                 out InBufferSize,
322                 out MaxInstances
323                 );
324             
325             if (!res) 
326             {
327                 throw new NamedPipeException();
328             }
329         }
330     }
331
332
333     /// <summary>
334     /// Represents local Named Pipe state informations.
335     /// </summary>
336     internal class NamedPipeSocketState 
337     {
338         public readonly int State;
339         public readonly int CurrentInstances;
340         public readonly int MaxCollectionCount;
341         public readonly int CollectDataTimeout;
342         public readonly string UserName;
343
344         internal NamedPipeSocketState(IntPtr hPipe) 
345         {
346             StringBuilder userName = new StringBuilder(256);
347             bool res = NamedPipeHelper.GetNamedPipeHandleState(
348                 hPipe,
349                 out State,
350                 out CurrentInstances,
351                 out MaxCollectionCount,
352                 out CollectDataTimeout,
353                 userName,
354                 userName.Capacity
355                 );
356             
357             if (res) 
358             {
359                 UserName = userName.ToString();
360             }
361             else 
362             {
363                 throw new NamedPipeException();
364             }
365         }
366     }
367 }
368
369 #endif