diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs
index 86e24f7f63..d1ba7ff2c6 100644
--- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs
+++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs
@@ -217,7 +217,6 @@ namespace Tgstation.Server.Host.Components.Session
if (!launchParameters.Port.HasValue)
throw new InvalidOperationException("Given port is null!");
- PortBindTest(launchParameters.Port.Value);
switch (dmbProvider.CompileJob.MinimumSecurityLevel)
{
case DreamDaemonSecurity.Ultrasafe:
@@ -255,8 +254,8 @@ namespace Tgstation.Server.Host.Components.Session
var engineType = dmbProvider.EngineVersion.Engine.Value;
if (engineType == EngineType.Byond)
await CheckPagerIsNotRunning();
- else if (engineType == EngineType.OpenDream && platformIdentifier.IsWindows)
- await asyncDelayer.Delay(TimeSpan.FromSeconds(2), cancellationToken); // prevent socket reuse after bind test
+
+ PortBindTest(launchParameters.Port.Value);
string outputFilePath = null;
var preserveLogFile = true;
diff --git a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs
index 948aedbc72..75adcf9a25 100644
--- a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs
+++ b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs
@@ -1,6 +1,8 @@
using System.Net;
using System.Net.Sockets;
+using Tgstation.Server.Host.System;
+
namespace Tgstation.Server.Host.Extensions
{
///
@@ -14,26 +16,27 @@ namespace Tgstation.Server.Host.Extensions
/// The port number to bind to.
/// If IPV6 should be tested as well.
public static void BindTest(ushort port, bool includeIPv6)
- {
- using var socket = new Socket(
- includeIPv6
- ? AddressFamily.InterNetworkV6
- : AddressFamily.InterNetwork,
- SocketType.Stream,
- ProtocolType.Tcp);
-
- socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true);
- socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false);
- socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true);
- if (includeIPv6)
- socket.DualMode = true;
-
- socket.Bind(
- new IPEndPoint(
+ => ProcessExecutor.WithProcessLaunchExclusivity(() =>
+ {
+ using var socket = new Socket(
includeIPv6
- ? IPAddress.IPv6Any
- : IPAddress.Any,
- port));
- }
+ ? AddressFamily.InterNetworkV6
+ : AddressFamily.InterNetwork,
+ SocketType.Stream,
+ ProtocolType.Tcp);
+
+ socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true);
+ socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false);
+ socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true);
+ if (includeIPv6)
+ socket.DualMode = true;
+
+ socket.Bind(
+ new IPEndPoint(
+ includeIPv6
+ ? IPAddress.IPv6Any
+ : IPAddress.Any,
+ port));
+ });
}
}
diff --git a/src/Tgstation.Server.Host/System/ProcessExecutor.cs b/src/Tgstation.Server.Host/System/ProcessExecutor.cs
index 581977bb5b..e680b09256 100644
--- a/src/Tgstation.Server.Host/System/ProcessExecutor.cs
+++ b/src/Tgstation.Server.Host/System/ProcessExecutor.cs
@@ -13,6 +13,11 @@ namespace Tgstation.Server.Host.System
///
sealed class ProcessExecutor : IProcessExecutor
{
+ ///
+ /// for .
+ ///
+ static readonly ReaderWriterLockSlim ExclusiveProcessLaunchLock = new ();
+
///
/// The for the .
///
@@ -33,6 +38,23 @@ namespace Tgstation.Server.Host.System
///
readonly ILoggerFactory loggerFactory;
+ ///
+ /// Runs a given making sure to not launch any processes while its running.
+ ///
+ /// The to execute.
+ public static void WithProcessLaunchExclusivity(Action action)
+ {
+ ExclusiveProcessLaunchLock.EnterWriteLock();
+ try
+ {
+ action();
+ }
+ finally
+ {
+ ExclusiveProcessLaunchLock.ExitWriteLock();
+ }
+ }
+
///
/// Initializes a new instance of the class.
///
@@ -127,7 +149,15 @@ namespace Tgstation.Server.Host.System
try
{
- handle.Start();
+ ExclusiveProcessLaunchLock.EnterReadLock();
+ try
+ {
+ handle.Start();
+ }
+ finally
+ {
+ ExclusiveProcessLaunchLock.ExitReadLock();
+ }
processStartTcs?.SetResult();
}