Merge pull request #3626 from lateralusX/jlorenss/win-api-family-support-eglib
[mono.git] / mcs / class / System.Core / System.IO.Pipes / PipeUnix.cs
1 //
2 // PipeUnix.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.Net;
36 using System.Runtime.InteropServices;
37 using System.Security.AccessControl;
38 using System.Security.Permissions;
39 using System.Security.Principal;
40 using System.Text;
41 using System.Threading;
42 using Microsoft.Win32;
43 using Microsoft.Win32.SafeHandles;
44 using Mono.Unix.Native;
45
46 namespace System.IO.Pipes
47 {
48         abstract class UnixAnonymousPipe : IPipe
49         {
50                 protected UnixAnonymousPipe ()
51                 {
52                 }
53
54                 public abstract SafePipeHandle Handle { get; }
55
56                 public void WaitForPipeDrain ()
57                 {
58                         throw new NotImplementedException ();
59                 }
60         }
61
62         class UnixAnonymousPipeClient : UnixAnonymousPipe, IAnonymousPipeClient
63         {
64                 // AnonymousPipeClientStream owner;
65
66                 public UnixAnonymousPipeClient (AnonymousPipeClientStream owner, SafePipeHandle handle)
67                 {
68                         // this.owner = owner;
69
70                         this.handle = handle;
71                 }
72
73                 SafePipeHandle handle;
74
75                 public override SafePipeHandle Handle {
76                         get { return handle; }
77                 }
78         }
79
80         class UnixAnonymousPipeServer : UnixAnonymousPipe, IAnonymousPipeServer
81         {
82                 // AnonymousPipeServerStream owner;
83
84                 public UnixAnonymousPipeServer (AnonymousPipeServerStream owner, PipeDirection direction, HandleInheritability inheritability, int bufferSize)
85                 {
86                         // this.owner = owner;
87
88                         throw new NotImplementedException ();
89                 }
90
91                 public UnixAnonymousPipeServer (AnonymousPipeServerStream owner, SafePipeHandle serverHandle, SafePipeHandle clientHandle)
92                 {
93                         // this.owner = owner;
94
95                         this.server_handle = serverHandle;
96                         this.client_handle = clientHandle;
97
98                         throw new NotImplementedException ();
99                 }
100
101                 SafePipeHandle server_handle, client_handle;
102
103                 public override SafePipeHandle Handle {
104                         get { return server_handle; }
105                 }
106
107                 public SafePipeHandle ClientHandle {
108                         get { return client_handle; }
109                 }
110
111                 public void DisposeLocalCopyOfClientHandle ()
112                 {
113                         throw new NotImplementedException ();
114                 }
115         }
116
117         abstract class UnixNamedPipe : IPipe
118         {
119                 public abstract SafePipeHandle Handle { get; }
120
121                 public void WaitForPipeDrain ()
122                 {
123                         throw new NotImplementedException ();
124                 }
125                 
126                 public void EnsureTargetFile (string name)
127                 {
128                         if (!File.Exists (name)) {
129                                 var error = Syscall.mknod (name, FilePermissions.S_IFIFO | FilePermissions.ALLPERMS, 0);
130                                 if (error != 0)
131                                         throw new IOException (String.Format ("Error on creating named pipe: error code {0}", error));
132                         }
133                 }
134
135                 protected void ValidateOptions (PipeOptions options, PipeTransmissionMode mode)
136                 {
137                         if ((options & PipeOptions.WriteThrough) != 0)
138                                 throw new NotImplementedException ("WriteThrough is not supported");
139
140                         if ((mode & PipeTransmissionMode.Message) != 0)
141                                 throw new NotImplementedException ("Message transmission mode is not supported");
142                         if ((options & PipeOptions.Asynchronous) != 0) // FIXME: use O_NONBLOCK?
143                                 throw new NotImplementedException ("Asynchronous pipe mode is not supported");
144                 }
145                 
146                 protected string RightsToAccess (PipeAccessRights rights)
147                 {
148                         string access = null;
149                         if ((rights & PipeAccessRights.ReadData) != 0) {
150                                 if ((rights & PipeAccessRights.WriteData) != 0)
151                                         access = "r+";
152                                 else
153                                         access = "r";
154                         }
155                         else if ((rights & PipeAccessRights.WriteData) != 0)
156                                 access = "w";
157                         else
158                                 throw new InvalidOperationException ("The pipe must be opened to either read or write");
159
160                         return access;
161                 }
162                 
163                 protected FileAccess RightsToFileAccess (PipeAccessRights rights)
164                 {
165                         if ((rights & PipeAccessRights.ReadData) != 0) {
166                                 if ((rights & PipeAccessRights.WriteData) != 0)
167                                         return FileAccess.ReadWrite;
168                                 else
169                                         return FileAccess.Read;
170                         }
171                         else if ((rights & PipeAccessRights.WriteData) != 0)
172                                 return FileAccess.Write;
173                         else
174                                 throw new InvalidOperationException ("The pipe must be opened to either read or write");
175                 }
176         }
177
178         class UnixNamedPipeClient : UnixNamedPipe, INamedPipeClient
179         {
180                 // .ctor with existing handle
181                 public UnixNamedPipeClient (NamedPipeClientStream owner, SafePipeHandle safePipeHandle)
182                 {
183                         this.owner = owner;
184                         this.handle = safePipeHandle;
185                         // FIXME: dunno how is_async could be filled.
186                 }
187
188                 // .ctor without handle - create new
189                 public UnixNamedPipeClient (NamedPipeClientStream owner, string serverName, string pipeName,
190                                              PipeAccessRights desiredAccessRights, PipeOptions options, HandleInheritability inheritability)
191                 {
192                         this.owner = owner;
193
194                         if (serverName != "." && !Dns.GetHostEntry (serverName).AddressList.Contains (IPAddress.Loopback))
195                                 throw new NotImplementedException ("Unix fifo does not support remote server connection");
196                         var name = Path.Combine ("/var/tmp/", pipeName);
197                         EnsureTargetFile (name);
198                         
199                         RightsToAccess (desiredAccessRights);
200                         
201                         ValidateOptions (options, owner.TransmissionMode);
202                         
203                         // FIXME: handle inheritability
204
205                         opener = delegate {
206                                 var fs = new FileStream (name, FileMode.Open, RightsToFileAccess (desiredAccessRights), FileShare.ReadWrite);
207                                 owner.Stream = fs;
208                                 handle = new SafePipeHandle (fs.SafeFileHandle.DangerousGetHandle (), false);
209                         };
210                 }
211
212                 NamedPipeClientStream owner;
213                 SafePipeHandle handle;
214                 Action opener;
215
216                 public override SafePipeHandle Handle {
217                         get { return handle; }
218                 }
219
220                 public void Connect ()
221                 {
222                         if (owner.IsConnected)
223                                 throw new InvalidOperationException ("The named pipe is already connected");
224
225                         opener ();
226                 }
227
228                 public void Connect (int timeout)
229                 {
230                         AutoResetEvent waitHandle = new AutoResetEvent (false);
231                         opener.BeginInvoke (delegate (IAsyncResult result) {
232                                 opener.EndInvoke (result);
233                                 waitHandle.Set ();
234                                 }, null);
235                         if (!waitHandle.WaitOne (TimeSpan.FromMilliseconds (timeout)))
236                                 throw new TimeoutException ();
237                 }
238
239                 public bool IsAsync {
240                         get { return false; }
241                 }
242
243                 public int NumberOfServerInstances {
244                         get { throw new NotImplementedException (); }
245                 }
246         }
247
248         class UnixNamedPipeServer : UnixNamedPipe, INamedPipeServer
249         {
250                 //NamedPipeServerStream owner;
251
252                 // .ctor with existing handle
253                 public UnixNamedPipeServer (NamedPipeServerStream owner, SafePipeHandle safePipeHandle)
254                 {
255                         this.handle = safePipeHandle;
256                         //this.owner = owner;
257                 }
258
259                 // .ctor without handle - create new
260                 public UnixNamedPipeServer (NamedPipeServerStream owner, string pipeName, int maxNumberOfServerInstances,
261                                              PipeTransmissionMode transmissionMode, PipeAccessRights rights, PipeOptions options,
262                                             int inBufferSize, int outBufferSize, HandleInheritability inheritability)
263                 {
264                         string name = Path.Combine ("/var/tmp/", pipeName);
265                         EnsureTargetFile (name);
266
267                         RightsToAccess (rights);
268
269                         ValidateOptions (options, owner.TransmissionMode);
270
271                         // FIXME: maxNumberOfServerInstances, modes, sizes, handle inheritability
272                         
273                         var fs = new FileStream (name, FileMode.Open, RightsToFileAccess (rights), FileShare.ReadWrite);
274                         handle = new SafePipeHandle (fs.SafeFileHandle.DangerousGetHandle (), false);
275                         owner.Stream = fs;
276                         should_close_handle = true;
277                 }
278
279                 SafePipeHandle handle;
280                 bool should_close_handle;
281
282                 public override SafePipeHandle Handle {
283                         get { return handle; }
284                 }
285
286                 public void Disconnect ()
287                 {
288                         if (should_close_handle)
289                                 Syscall.fclose (handle.DangerousGetHandle ());
290                 }
291
292                 public void WaitForConnection ()
293                 {
294                         // FIXME: what can I do here?
295                 }
296         }
297 }
298
299 #endif