Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit 5f4a716

Browse files
committed
Add test for socket non-inheritance
1 parent 35e25da commit 5f4a716

File tree

1 file changed

+93
-4
lines changed

1 file changed

+93
-4
lines changed

src/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs

Lines changed: 93 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using System.Diagnostics;
6+
using System.IO;
7+
using System.IO.Pipes;
8+
using System.Threading.Tasks;
59
using Xunit;
610

711
namespace System.Net.Sockets.Tests
812
{
9-
public class CreateSocket
13+
public class CreateSocket : RemoteExecutorTestBase
1014
{
1115
public static object[][] DualModeSuccessInputs = {
1216
new object[] { SocketType.Stream, ProtocolType.Tcp },
@@ -89,9 +93,94 @@ public void Ctor_Failure(AddressFamily addressFamily, SocketType socketType, Pro
8993
[ConditionalTheory(nameof(SupportsRawSockets))]
9094
public void Ctor_Raw_Success(AddressFamily addressFamily, ProtocolType protocolType)
9195
{
92-
using (new Socket(addressFamily, SocketType.Raw, protocolType))
93-
{
94-
}
96+
using (new Socket(addressFamily, SocketType.Raw, protocolType))
97+
{
98+
}
99+
}
100+
101+
[Theory]
102+
[InlineData(true, 0)] // Accept
103+
[InlineData(false, 0)]
104+
[InlineData(true, 1)] // AcceptAsync
105+
[InlineData(false, 1)]
106+
[InlineData(true, 2)] // Begin/EndAccept
107+
[InlineData(false, 2)]
108+
public void CtorAndAccept_SocketNotKeptAliveViaInheritance(bool validateClientOuter, int acceptApiOuter)
109+
{
110+
// Run the test in another process so as to not have trouble with other tests
111+
// launching child processes that might impact inheritance.
112+
RemoteInvoke((validateClientString, acceptApiString) =>
113+
{
114+
bool validateClient = bool.Parse(validateClientString);
115+
int acceptApi = int.Parse(acceptApiString);
116+
117+
// Create a listening server.
118+
using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
119+
{
120+
listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
121+
listener.Listen(int.MaxValue);
122+
EndPoint ep = listener.LocalEndPoint;
123+
124+
// Create a client and connect to that listener.
125+
using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
126+
{
127+
client.Connect(ep);
128+
129+
// Accept the connection using one of multiple accept mechanisms.
130+
Socket server =
131+
acceptApi == 0 ? listener.Accept() :
132+
acceptApi == 1 ? listener.AcceptAsync().GetAwaiter().GetResult() :
133+
acceptApi == 2 ? Task.Factory.FromAsync(listener.BeginAccept, listener.EndAccept, null).GetAwaiter().GetResult() :
134+
throw new Exception($"Unexpected {nameof(acceptApi)}: {acceptApi}");
135+
136+
// Get streams for the client and server, and create a pipe that we'll use
137+
// to communicate with a child process.
138+
using (var serverStream = new NetworkStream(server, ownsSocket: true))
139+
using (var clientStream = new NetworkStream(client, ownsSocket: true))
140+
using (var serverPipe = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable))
141+
{
142+
// Create a child process that blocks waiting to receive a signal on the anonymous pipe.
143+
// The whole purpose of the child is to test whether handles are inherited, so we
144+
// keep the child process alive until we're done validating that handles close as expected.
145+
using (RemoteInvoke(clientPipeHandle =>
146+
{
147+
using (var clientPipe = new AnonymousPipeClientStream(PipeDirection.In, clientPipeHandle))
148+
{
149+
Assert.Equal(42, clientPipe.ReadByte());
150+
}
151+
}, serverPipe.GetClientHandleAsString()))
152+
{
153+
if (validateClient) // Validate that the child isn't keeping alive the "new Socket" for the client
154+
{
155+
// Send data from the server to client, then validate the client gets EOF when the server closes.
156+
serverStream.WriteByte(84);
157+
Assert.Equal(84, clientStream.ReadByte());
158+
serverStream.Close();
159+
Assert.Equal(-1, clientStream.ReadByte());
160+
}
161+
else // Validate that the child isn't keeping alive the "listener.Accept" for the server
162+
{
163+
// Send data from the client to server, then validate the server gets EOF when the client closes.
164+
clientStream.WriteByte(84);
165+
Assert.Equal(84, serverStream.ReadByte());
166+
clientStream.Close();
167+
Assert.Equal(-1, serverStream.ReadByte());
168+
}
169+
170+
// And validate that we after closing the listening socket, we're not able to connect.
171+
listener.Dispose();
172+
using (var tmpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
173+
{
174+
Assert.ThrowsAny<SocketException>(() => tmpClient.Connect(ep));
175+
}
176+
177+
// Let the child process terminate.
178+
serverPipe.WriteByte(42);
179+
}
180+
}
181+
}
182+
}
183+
}, validateClientOuter.ToString(), acceptApiOuter.ToString()).Dispose();
95184
}
96185
}
97186
}

0 commit comments

Comments
 (0)