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