mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-24 21:46:52 +01:00
Possibly fix address reuse issue forever
Child processes may have been ~~inheriting~~ stealing the bind test handle.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
using Tgstation.Server.Host.System;
|
||||
|
||||
namespace Tgstation.Server.Host.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
@@ -14,26 +16,27 @@ namespace Tgstation.Server.Host.Extensions
|
||||
/// <param name="port">The port number to bind to.</param>
|
||||
/// <param name="includeIPv6">If IPV6 should be tested as well.</param>
|
||||
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));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,11 @@ namespace Tgstation.Server.Host.System
|
||||
/// <inheritdoc />
|
||||
sealed class ProcessExecutor : IProcessExecutor
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="ReaderWriterLockSlim"/> for <see cref="WithProcessLaunchExclusivity(Action)"/>.
|
||||
/// </summary>
|
||||
static readonly ReaderWriterLockSlim ExclusiveProcessLaunchLock = new ();
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IProcessFeatures"/> for the <see cref="ProcessExecutor"/>.
|
||||
/// </summary>
|
||||
@@ -33,6 +38,23 @@ namespace Tgstation.Server.Host.System
|
||||
/// </summary>
|
||||
readonly ILoggerFactory loggerFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Runs a given <paramref name="action"/> making sure to not launch any processes while its running.
|
||||
/// </summary>
|
||||
/// <param name="action">The <see cref="Action"/> to execute.</param>
|
||||
public static void WithProcessLaunchExclusivity(Action action)
|
||||
{
|
||||
ExclusiveProcessLaunchLock.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
action();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ExclusiveProcessLaunchLock.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProcessExecutor"/> class.
|
||||
/// </summary>
|
||||
@@ -127,7 +149,15 @@ namespace Tgstation.Server.Host.System
|
||||
|
||||
try
|
||||
{
|
||||
handle.Start();
|
||||
ExclusiveProcessLaunchLock.EnterReadLock();
|
||||
try
|
||||
{
|
||||
handle.Start();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ExclusiveProcessLaunchLock.ExitReadLock();
|
||||
}
|
||||
|
||||
processStartTcs?.SetResult();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user