|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Pipes;
using System.Reflection;
using System.Net.Sockets;
using Roslyn.Test.Utilities;
namespace Microsoft.CodeAnalysis.CompilerServer.UnitTests
{
/// <summary>
/// This is a HACK that allows you to get at the underlying Socket for a given NamedPipeServerStream
/// instance. It is very useful it proactively diagnosing bugs in the server code by letting us inspect
/// the socket to see if it's disposed, not available, etc ... vs. experiencing flaky bugs that are
/// incredibly difficult to track down.
///
/// Do NOT check this into production, it's a unit test utility only
/// </summary>
internal static class NamedPipeTestUtil
{
private static IDictionary GetSharedServersDictionary()
{
var sharedServerFullName = typeof(NamedPipeServerStream).FullName + "+SharedServer";
var sharedServerType = typeof(NamedPipeServerStream).Assembly.GetType(sharedServerFullName);
var serversField = sharedServerType?.GetField("s_servers", BindingFlags.NonPublic | BindingFlags.Static);
var servers = (IDictionary?)serversField?.GetValue(null);
if (servers is null)
{
throw new Exception("Cannot locate the SharedServer dictionary");
}
return servers;
}
private static Socket GetSocket(object sharedServer)
{
var listeningSocketProperty = sharedServer!.GetType()?.GetProperty("ListeningSocket", BindingFlags.NonPublic | BindingFlags.Instance);
var socket = (Socket?)listeningSocketProperty?.GetValue(sharedServer, null);
if (socket is null)
{
throw new Exception("Socket is unexpectedly null");
}
return socket;
}
private static Socket? GetSocketForPipeName(string pipeName)
{
if (!ExecutionConditionUtil.IsUnix || !ExecutionConditionUtil.IsCoreClr)
{
return null;
}
pipeName = "/tmp/" + pipeName;
var servers = GetSharedServersDictionary();
lock (servers)
{
if (!servers.Contains(pipeName))
{
return null;
}
var sharedServer = servers[pipeName];
Debug.Assert(sharedServer is object);
return GetSocket(sharedServer);
}
}
internal static bool IsPipeFullyClosed(string pipeName) => GetSocketForPipeName(pipeName) is null;
internal static void DisposeAll()
{
if (!ExecutionConditionUtil.IsUnix || !ExecutionConditionUtil.IsCoreClr)
{
return;
}
var servers = GetSharedServersDictionary();
lock (servers)
{
var e = servers.GetEnumerator();
while (e.MoveNext())
{
var sharedServer = e.Value!;
var socket = GetSocket(sharedServer);
socket.Dispose();
}
servers.Clear();
}
}
}
}
|