diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs index 9a6ecd8b62..085dc79c32 100644 --- a/src/Tgstation.Server.Host/Components/InstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs @@ -5,8 +5,6 @@ using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.Linq; -using System.Net; -using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; using Tgstation.Server.Api.Models; @@ -16,6 +14,7 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Controllers; using Tgstation.Server.Host.Core; using Tgstation.Server.Host.Database; +using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Security; @@ -482,8 +481,7 @@ namespace Tgstation.Server.Host.Components // This runs before the real socket is opened, ensures we don't perform reattaches unless we're fairly certain the bind won't fail // If it does fail, DD will be killed. - using var hostingSocket = new Socket(SocketType.Stream, ProtocolType.Tcp); - hostingSocket.Bind(new IPEndPoint(IPAddress.Any, serverPortProvider.HttpApiPort)); + SocketExtensions.BindTest(serverPortProvider.HttpApiPort); } /// diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index 3b859791ab..84c2ca9667 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -2,7 +2,6 @@ using System; using System.Globalization; using System.Linq; -using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; @@ -16,6 +15,7 @@ using Tgstation.Server.Host.Components.Deployment; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Components.Interop.Bridge; using Tgstation.Server.Host.Core; +using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Security; @@ -118,11 +118,9 @@ namespace Tgstation.Server.Host.Components.Session /// The port number to test. static void PortBindTest(ushort port) { - using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - try { - socket.Bind(new IPEndPoint(IPAddress.Any, port)); + SocketExtensions.BindTest(port); } catch (SocketException ex) { diff --git a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs new file mode 100644 index 0000000000..6d4ae76323 --- /dev/null +++ b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs @@ -0,0 +1,23 @@ +using System.Net; +using System.Net.Sockets; + +namespace Tgstation.Server.Host.Extensions +{ + /// + /// Extension methods for the . + /// + static class SocketExtensions + { + /// + /// Attempt to exclusively bind to a given . + /// + /// The port number to bind to. + public static void BindTest(ushort port) + { + using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true); + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); + socket.Bind(new IPEndPoint(IPAddress.Any, port)); + } + } +} diff --git a/tests/Tgstation.Server.Tests/Instance/JobsRequiredTest.cs b/tests/Tgstation.Server.Tests/Instance/JobsRequiredTest.cs index 258e69de57..6594f345e2 100644 --- a/tests/Tgstation.Server.Tests/Instance/JobsRequiredTest.cs +++ b/tests/Tgstation.Server.Tests/Instance/JobsRequiredTest.cs @@ -36,7 +36,8 @@ namespace Tgstation.Server.Tests.Instance } if (expectFailure ^ job.ExceptionDetails != null) - Assert.Fail(job.ExceptionDetails ?? $"Expected job \"{job.Id}\" \"{job.Description}\" to fail but it didn't"); + Assert.Fail(job.ExceptionDetails + ?? $"Expected job \"{job.Id}\" \"{job.Description}\" to fail {(expectedCode.HasValue ? $"with ErrorCode \"{expectedCode.Value}\" " : String.Empty)}but it didn't"); if (expectedCode.HasValue) Assert.AreEqual(expectedCode.Value, job.ErrorCode, job.ExceptionDetails); diff --git a/tests/Tgstation.Server.Tests/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Instance/WatchdogTest.cs index d8e666560f..532c18d704 100644 --- a/tests/Tgstation.Server.Tests/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Instance/WatchdogTest.cs @@ -141,6 +141,8 @@ namespace Tgstation.Server.Tests.Instance Job startJob; using (var blockSocket = new Socket(SocketType.Stream, ProtocolType.Tcp)) { + blockSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true); + blockSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); blockSocket.Bind(new IPEndPoint(IPAddress.Any, 1337)); startJob = await instanceClient.DreamDaemon.Start(cancellationToken).ConfigureAwait(false); diff --git a/tests/Tgstation.Server.Tests/IntegrationTest.cs b/tests/Tgstation.Server.Tests/IntegrationTest.cs index b842dd6345..3f02965eca 100644 --- a/tests/Tgstation.Server.Tests/IntegrationTest.cs +++ b/tests/Tgstation.Server.Tests/IntegrationTest.cs @@ -200,6 +200,8 @@ namespace Tgstation.Server.Tests // http bind test https://github.com/tgstation/tgstation-server/issues/1065 using (var blockingSocket = new Socket(SocketType.Stream, ProtocolType.Tcp)) { + blockingSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true); + blockingSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); blockingSocket.Bind(new IPEndPoint(IPAddress.Any, server.Url.Port)); try {