1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using Microsoft.Win32.SafeHandles;
6 using Xunit;
7 
8 namespace System.IO.Pipes.Tests
9 {
10     /// <summary>
11     /// Tests for the constructors for NamedPipeServerStream
12     /// </summary>
13     public class NamedPipeTest_CreateServer : NamedPipeTestBase
14     {
15         [Theory]
16         [InlineData(PipeDirection.In)]
17         [InlineData(PipeDirection.InOut)]
18         [InlineData(PipeDirection.Out)]
NullPipeName_Throws_ArgumentNullException(PipeDirection direction)19         public static void NullPipeName_Throws_ArgumentNullException(PipeDirection direction)
20         {
21             AssertExtensions.Throws<ArgumentNullException>("pipeName", () => new NamedPipeServerStream(null));
22             AssertExtensions.Throws<ArgumentNullException>("pipeName", () => new NamedPipeServerStream(null, direction));
23             AssertExtensions.Throws<ArgumentNullException>("pipeName", () => new NamedPipeServerStream(null, direction, 2));
24             AssertExtensions.Throws<ArgumentNullException>("pipeName", () => new NamedPipeServerStream(null, direction, 3, PipeTransmissionMode.Byte));
25             AssertExtensions.Throws<ArgumentNullException>("pipeName", () => new NamedPipeServerStream(null, direction, 3, PipeTransmissionMode.Byte, PipeOptions.None));
26             AssertExtensions.Throws<ArgumentNullException>("pipeName", () => new NamedPipeServerStream(null, direction, 3, PipeTransmissionMode.Byte, PipeOptions.None, 0, 0));
27         }
28 
29         [Theory]
30         [InlineData(PipeDirection.In)]
31         [InlineData(PipeDirection.InOut)]
32         [InlineData(PipeDirection.Out)]
ZeroLengthPipeName_Throws_ArgumentException(PipeDirection direction)33         public static void ZeroLengthPipeName_Throws_ArgumentException(PipeDirection direction)
34         {
35             AssertExtensions.Throws<ArgumentException>(null, () => new NamedPipeServerStream(""));
36             AssertExtensions.Throws<ArgumentException>(null, () => new NamedPipeServerStream("", direction));
37             AssertExtensions.Throws<ArgumentException>(null, () => new NamedPipeServerStream("", direction, 2));
38             AssertExtensions.Throws<ArgumentException>(null, () => new NamedPipeServerStream("", direction, 3, PipeTransmissionMode.Byte));
39             AssertExtensions.Throws<ArgumentException>(null, () => new NamedPipeServerStream("", direction, 3, PipeTransmissionMode.Byte, PipeOptions.None));
40             AssertExtensions.Throws<ArgumentException>(null, () => new NamedPipeServerStream("", direction, 3, PipeTransmissionMode.Byte, PipeOptions.None, 0, 0));
41         }
42 
43         [Theory]
44         [InlineData(PipeDirection.In)]
45         [InlineData(PipeDirection.InOut)]
46         [InlineData(PipeDirection.Out)]
47         [PlatformSpecific(TestPlatforms.Windows)] // "anonymous" only reserved on Windows
ReservedPipeName_Throws_ArgumentOutOfRangeException(PipeDirection direction)48         public static void ReservedPipeName_Throws_ArgumentOutOfRangeException(PipeDirection direction)
49         {
50             const string reservedName = "anonymous";
51             AssertExtensions.Throws<ArgumentOutOfRangeException>("pipeName", () => new NamedPipeServerStream(reservedName));
52             AssertExtensions.Throws<ArgumentOutOfRangeException>("pipeName", () => new NamedPipeServerStream(reservedName, direction));
53             AssertExtensions.Throws<ArgumentOutOfRangeException>("pipeName", () => new NamedPipeServerStream(reservedName, direction, 1));
54             AssertExtensions.Throws<ArgumentOutOfRangeException>("pipeName", () => new NamedPipeServerStream(reservedName, direction, 1, PipeTransmissionMode.Byte));
55             AssertExtensions.Throws<ArgumentOutOfRangeException>("pipeName", () => new NamedPipeServerStream(reservedName, direction, 1, PipeTransmissionMode.Byte, PipeOptions.None));
56             AssertExtensions.Throws<ArgumentOutOfRangeException>("pipeName", () => new NamedPipeServerStream(reservedName, direction, 1, PipeTransmissionMode.Byte, PipeOptions.None, 0, 0));}
57 
58         [Fact]
Create_PipeName()59         public static void Create_PipeName()
60         {
61             new NamedPipeServerStream(GetUniquePipeName()).Dispose();
62         }
63 
64         [Fact]
Create_PipeName_Direction_MaxInstances()65         public static void Create_PipeName_Direction_MaxInstances()
66         {
67             new NamedPipeServerStream(GetUniquePipeName(), PipeDirection.Out, 1).Dispose();
68         }
69 
70         [Fact]
71         [PlatformSpecific(TestPlatforms.Windows)] // can't access SafePipeHandle on Unix until after connection created
CreateWithNegativeOneServerInstances_DefaultsToMaxServerInstances()72         public static void CreateWithNegativeOneServerInstances_DefaultsToMaxServerInstances()
73         {
74             // When passed -1 as the maxnumberofserverisntances, the NamedPipeServerStream.Windows class
75             // will translate that to the platform specific maximum number (255)
76             using (var server = new NamedPipeServerStream(GetUniquePipeName(), PipeDirection.InOut, -1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous))
77             using (var server2 = new NamedPipeServerStream(PipeDirection.InOut, false, true, server.SafePipeHandle))
78             using (var server3 = new NamedPipeServerStream(PipeDirection.InOut, false, true, server.SafePipeHandle))
79             {
80             }
81         }
82 
83         [Fact]
InvalidPipeDirection_Throws_ArgumentOutOfRangeException()84         public static void InvalidPipeDirection_Throws_ArgumentOutOfRangeException()
85         {
86             AssertExtensions.Throws<ArgumentOutOfRangeException>("direction", () => new NamedPipeServerStream("temp1", (PipeDirection)123));
87             AssertExtensions.Throws<ArgumentOutOfRangeException>("direction", () => new NamedPipeServerStream("temp1", (PipeDirection)123, 1));
88             AssertExtensions.Throws<ArgumentOutOfRangeException>("direction", () => new NamedPipeServerStream("temp1", (PipeDirection)123, 1, PipeTransmissionMode.Byte));
89             AssertExtensions.Throws<ArgumentOutOfRangeException>("direction", () => new NamedPipeServerStream("temp1", (PipeDirection)123, 1, PipeTransmissionMode.Byte, PipeOptions.None));
90             AssertExtensions.Throws<ArgumentOutOfRangeException>("direction", () => new NamedPipeServerStream("tempx", (PipeDirection)123, 1, PipeTransmissionMode.Byte, PipeOptions.None, 0, 0));
91         }
92 
93         [Theory]
94         [InlineData(0)]
95         [InlineData(-2)]
InvalidServerInstances_Throws_ArgumentOutOfRangeException(int numberOfServerInstances)96         public static void InvalidServerInstances_Throws_ArgumentOutOfRangeException(int numberOfServerInstances)
97         {
98             AssertExtensions.Throws<ArgumentOutOfRangeException>("maxNumberOfServerInstances", () => new NamedPipeServerStream("temp3", PipeDirection.In, numberOfServerInstances));
99             AssertExtensions.Throws<ArgumentOutOfRangeException>("maxNumberOfServerInstances", () => new NamedPipeServerStream("temp3", PipeDirection.In, numberOfServerInstances, PipeTransmissionMode.Byte));
100             AssertExtensions.Throws<ArgumentOutOfRangeException>("maxNumberOfServerInstances", () => new NamedPipeServerStream("temp3", PipeDirection.In, numberOfServerInstances, PipeTransmissionMode.Byte, PipeOptions.None));
101             AssertExtensions.Throws<ArgumentOutOfRangeException>("maxNumberOfServerInstances", () => new NamedPipeServerStream("temp3", PipeDirection.In, numberOfServerInstances, PipeTransmissionMode.Byte, PipeOptions.None, 0, 0));
102         }
103 
104         [Theory]
105         [InlineData(PipeDirection.In)]
106         [InlineData(PipeDirection.InOut)]
107         [InlineData(PipeDirection.Out)]
ServerInstancesOver254_Throws_ArgumentOutOfRangeException(PipeDirection direction)108         public static void ServerInstancesOver254_Throws_ArgumentOutOfRangeException(PipeDirection direction)
109         {
110             AssertExtensions.Throws<ArgumentOutOfRangeException>("maxNumberOfServerInstances", () => new NamedPipeServerStream("temp3", direction, 255));
111             AssertExtensions.Throws<ArgumentOutOfRangeException>("maxNumberOfServerInstances", () => new NamedPipeServerStream("temp3", direction, 255, PipeTransmissionMode.Byte));
112             AssertExtensions.Throws<ArgumentOutOfRangeException>("maxNumberOfServerInstances", () => new NamedPipeServerStream("temp3", direction, 255, PipeTransmissionMode.Byte, PipeOptions.None));
113             AssertExtensions.Throws<ArgumentOutOfRangeException>("maxNumberOfServerInstances", () => new NamedPipeServerStream("temp3", direction, 255, PipeTransmissionMode.Byte, PipeOptions.None, 0, 0));
114         }
115 
116         [Theory]
117         [InlineData(PipeDirection.In)]
118         [InlineData(PipeDirection.InOut)]
119         [InlineData(PipeDirection.Out)]
InvalidTransmissionMode_Throws_ArgumentOutOfRangeException(PipeDirection direction)120         public static void InvalidTransmissionMode_Throws_ArgumentOutOfRangeException(PipeDirection direction)
121         {
122             AssertExtensions.Throws<ArgumentOutOfRangeException>("transmissionMode", () => new NamedPipeServerStream("temp1", direction, 1, (PipeTransmissionMode)123));
123             AssertExtensions.Throws<ArgumentOutOfRangeException>("transmissionMode", () => new NamedPipeServerStream("temp1", direction, 1, (PipeTransmissionMode)123, PipeOptions.None));
124             AssertExtensions.Throws<ArgumentOutOfRangeException>("transmissionMode", () => new NamedPipeServerStream("tempx", direction, 1, (PipeTransmissionMode)123, PipeOptions.None, 0, 0));
125         }
126 
127         [Theory]
128         [InlineData(PipeDirection.In)]
129         [InlineData(PipeDirection.InOut)]
130         [InlineData(PipeDirection.Out)]
InvalidPipeOptions_Throws_ArgumentOutOfRangeException(PipeDirection direction)131         public static void InvalidPipeOptions_Throws_ArgumentOutOfRangeException(PipeDirection direction)
132         {
133             AssertExtensions.Throws<ArgumentOutOfRangeException>("options", () => new NamedPipeServerStream("temp1", direction, 1, PipeTransmissionMode.Byte, (PipeOptions)255));
134             AssertExtensions.Throws<ArgumentOutOfRangeException>("options", () => new NamedPipeServerStream("tempx", direction, 1, PipeTransmissionMode.Byte, (PipeOptions)255, 0, 0));
135         }
136 
137         [Theory]
138         [InlineData(PipeDirection.In)]
139         [InlineData(PipeDirection.InOut)]
140         [InlineData(PipeDirection.Out)]
InvalidBufferSize_Throws_ArgumentOutOfRangeException(PipeDirection direction)141         public static void InvalidBufferSize_Throws_ArgumentOutOfRangeException(PipeDirection direction)
142         {
143             AssertExtensions.Throws<ArgumentOutOfRangeException>("inBufferSize", () => new NamedPipeServerStream("temp2", direction, 1, PipeTransmissionMode.Byte, PipeOptions.None, -1, 0));
144             AssertExtensions.Throws<ArgumentOutOfRangeException>("outBufferSize", () => new NamedPipeServerStream("temp2", direction, 1, PipeTransmissionMode.Byte, PipeOptions.None, 0, -123));
145         }
146 
147         [Theory]
148         [InlineData(PipeDirection.In)]
149         [InlineData(PipeDirection.InOut)]
150         [InlineData(PipeDirection.Out)]
NullPipeHandle_Throws_ArgumentNullException(PipeDirection direction)151         public static void NullPipeHandle_Throws_ArgumentNullException(PipeDirection direction)
152         {
153             AssertExtensions.Throws<ArgumentNullException>("safePipeHandle", () => new NamedPipeServerStream(direction, false, true, null));
154         }
155 
156         [Theory]
157         [InlineData(PipeDirection.In)]
158         [InlineData(PipeDirection.InOut)]
159         [InlineData(PipeDirection.Out)]
InvalidPipeHandle_Throws_ArgumentException(PipeDirection direction)160         public static void InvalidPipeHandle_Throws_ArgumentException(PipeDirection direction)
161         {
162             SafePipeHandle pipeHandle = new SafePipeHandle(new IntPtr(-1), true);
163             AssertExtensions.Throws<ArgumentException>("safePipeHandle", () => new NamedPipeServerStream(direction, false, true, pipeHandle));
164         }
165 
166         [Theory]
167         [InlineData(PipeDirection.In)]
168         [InlineData(PipeDirection.InOut)]
169         [InlineData(PipeDirection.Out)]
BadHandleKind_Throws_IOException(PipeDirection direction)170         public static void BadHandleKind_Throws_IOException(PipeDirection direction)
171         {
172             using (FileStream fs = new FileStream(Path.Combine(Path.GetTempPath(), "_BadHandleKind_Throws_IOException_" + Path.GetRandomFileName()), FileMode.Create, FileAccess.Write, FileShare.None, 8, FileOptions.DeleteOnClose))
173             {
174                 SafeFileHandle safeHandle = fs.SafeFileHandle;
175 
176                 bool gotRef = false;
177                 try
178                 {
179                     safeHandle.DangerousAddRef(ref gotRef);
180                     IntPtr handle = safeHandle.DangerousGetHandle();
181 
182                     SafePipeHandle fakePipeHandle = new SafePipeHandle(handle, ownsHandle: false);
183                     Assert.Throws<IOException>(() => new NamedPipeServerStream(direction, false, true, fakePipeHandle));
184                 }
185                 finally
186                 {
187                     if (gotRef)
188                         safeHandle.DangerousRelease();
189                 }
190             }
191         }
192 
193         [Theory]
194         [InlineData(PipeDirection.In)]
195         [InlineData(PipeDirection.InOut)]
196         [InlineData(PipeDirection.Out)]
197         [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "This scenario is not handled with System.ArgumentException on Full Framework")]
198         [PlatformSpecific(TestPlatforms.Windows)] // accessing SafePipeHandle on Unix fails for a non-connected stream
Windows_CreateFromDisposedServerHandle_Throws_ObjectDisposedException(PipeDirection direction)199         public static void Windows_CreateFromDisposedServerHandle_Throws_ObjectDisposedException(PipeDirection direction)
200         {
201             // The pipe is closed when we try to make a new Stream with it
202             var pipe = new NamedPipeServerStream(GetUniquePipeName(), direction, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
203             SafePipeHandle handle = pipe.SafePipeHandle;
204             pipe.Dispose();
205             Assert.Throws<ObjectDisposedException>(() => new NamedPipeServerStream(direction, true, true, pipe.SafePipeHandle).Dispose());
206         }
207 
208         [Theory]
209         [InlineData(PipeDirection.In)]
210         [InlineData(PipeDirection.InOut)]
211         [InlineData(PipeDirection.Out)]
212         [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework, ".NET Core handles this scenario by throwing ArgumentException instead")]
213         [PlatformSpecific(TestPlatforms.Windows)] // accessing SafePipeHandle on Unix fails for a non-connected stream
Windows_CreateFromAlreadyBoundHandle_Throws_ApplicationException(PipeDirection direction)214         public static void Windows_CreateFromAlreadyBoundHandle_Throws_ApplicationException(PipeDirection direction)
215         {
216             // The pipe is already bound
217             using (var pipe = new NamedPipeServerStream(GetUniquePipeName(), direction, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous))
218             {
219                 SafePipeHandle handle = pipe.SafePipeHandle;
220                 Assert.Throws<ApplicationException>(() => new NamedPipeServerStream(direction, true, true, handle));
221              }
222          }
223 
224         [Fact]
225         [PlatformSpecific(TestPlatforms.AnyUnix)] // accessing SafePipeHandle on Unix fails for a non-connected stream
Unix_GetHandleOfNewServerStream_Throws_InvalidOperationException()226         public static void Unix_GetHandleOfNewServerStream_Throws_InvalidOperationException()
227         {
228             using (var pipe = new NamedPipeServerStream(GetUniquePipeName(), PipeDirection.Out, 1, PipeTransmissionMode.Byte))
229             {
230                 Assert.Throws<InvalidOperationException>(() => pipe.SafePipeHandle);
231             }
232         }
233 
234         [Theory]
235         [InlineData(PipeDirection.In)]
236         [InlineData(PipeDirection.InOut)]
237         [InlineData(PipeDirection.Out)]
238         [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, ".NET framework handles this scenario by throwing ApplicationException instead")]
239         [PlatformSpecific(TestPlatforms.Windows)] // accessing SafePipeHandle on Unix fails for a non-connected stream
Windows_CreateFromAlreadyBoundHandle_Throws_ArgumentException(PipeDirection direction)240         public static void Windows_CreateFromAlreadyBoundHandle_Throws_ArgumentException(PipeDirection direction)
241         {
242             // The pipe is already bound
243             using (var pipe = new NamedPipeServerStream(GetUniquePipeName(), direction, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous))
244             {
245                 AssertExtensions.Throws<ArgumentException>("handle", () => new NamedPipeServerStream(direction, true, true, pipe.SafePipeHandle));
246             }
247         }
248 
249         [Fact]
250         [PlatformSpecific(TestPlatforms.Windows)] // NumberOfServerInstances > 1 isn't supported and has undefined behavior on Unix
ServerCountOverMaxServerInstances_Throws_IOException()251         public static void ServerCountOverMaxServerInstances_Throws_IOException()
252         {
253             string uniqueServerName = GetUniquePipeName();
254             using (NamedPipeServerStream server = new NamedPipeServerStream(uniqueServerName, PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous))
255             {
256                 Assert.Throws<IOException>(() => new NamedPipeServerStream(uniqueServerName));
257             }
258         }
259 
260         [Fact]
261         [PlatformSpecific(TestPlatforms.Windows)] // NumberOfServerInstances > 1 isn't supported and has undefined behavior on Unix
Windows_ServerCloneWithDifferentDirection_Throws_UnauthorizedAccessException()262         public static void Windows_ServerCloneWithDifferentDirection_Throws_UnauthorizedAccessException()
263         {
264             string uniqueServerName = GetUniquePipeName();
265             using (NamedPipeServerStream server = new NamedPipeServerStream(uniqueServerName, PipeDirection.In, 2, PipeTransmissionMode.Byte, PipeOptions.Asynchronous))
266             {
267                 Assert.Throws<UnauthorizedAccessException>(() => new NamedPipeServerStream(uniqueServerName, PipeDirection.Out));
268             }
269         }
270     }
271 }
272