Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
## [1.2.0] - 2022-08-10

### New features
* If using the default network interface, the transport will attempt to transparently recreate the underlying network socket if it fails. This should increase robustness, especially on mobile where the OS might close sockets when an application is sent to the background.

### Changes
* A new `NetworkSocketError` value has been added to `Error.StatusCode`. This will be returned through `NetworkDriver.ReceiveErrorCode` when the automatic socket recreation mentioned above has failed (indicating an unrecoverable network failure).

### Fixes
* On iOS, communications will restart correctly if the application was in the background. Note that if using Relay, it's still possible for the allocation to have timed out while in the background. Recreation of a new allocation with a new `NetworkDriver` is still required in that scenario.
* Fixed a possible stack overflow if the receive queue parameter was configured with a very large value (>10,000).
  • Loading branch information
Unity Technologies committed Aug 10, 2022
1 parent 1cc602e commit 2eca5b0
Show file tree
Hide file tree
Showing 14 changed files with 268 additions and 199 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Change log

## [1.2.0] - 2022-08-10

### New features
* If using the default network interface, the transport will attempt to transparently recreate the underlying network socket if it fails. This should increase robustness, especially on mobile where the OS might close sockets when an application is sent to the background.

### Changes
* A new `NetworkSocketError` value has been added to `Error.StatusCode`. This will be returned through `NetworkDriver.ReceiveErrorCode` when the automatic socket recreation mentioned above has failed (indicating an unrecoverable network failure).

### Fixes
* On iOS, communications will restart correctly if the application was in the background. Note that if using Relay, it's still possible for the allocation to have timed out while in the background. Recreation of a new allocation with a new `NetworkDriver` is still required in that scenario.
* Fixed a possible stack overflow if the receive queue parameter was configured with a very large value (>10,000).

## [1.1.0] - 2022-06-14

### New features
Expand Down
38 changes: 0 additions & 38 deletions Runtime/AppForegroundTracker.cs

This file was deleted.

11 changes: 0 additions & 11 deletions Runtime/AppForegroundTracker.cs.meta

This file was deleted.

284 changes: 167 additions & 117 deletions Runtime/BaselibNetworkInterface.cs

Large diffs are not rendered by default.

12 changes: 3 additions & 9 deletions Runtime/DataStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,13 @@ internal struct UIntFloat
[StructLayout(LayoutKind.Sequential)]
public unsafe struct DataStreamWriter
{
struct IsLittleEndianStructKey {}
private static readonly SharedStatic<int> m_IsLittleEndian = SharedStatic<int>.GetOrCreate<IsLittleEndianStructKey>();
public static bool IsLittleEndian
{
get
{
if (m_IsLittleEndian.Data == 0)
{
uint test = 1;
byte* testPtr = (byte*)&test;
m_IsLittleEndian.Data = testPtr[0] == 1 ? 1 : 2;
}
return m_IsLittleEndian.Data == 1;
uint test = 1;
byte* testPtr = (byte*)&test;
return testPtr[0] == 1;
}
}

Expand Down
5 changes: 4 additions & 1 deletion Runtime/NetworkConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,11 @@ public enum StatusCode
/// <summary>Internal send handle is invalid.</summary>
NetworkSendHandleInvalid = -8,

/// <summary>Tried to create an <see cref="IPCNetworkInterface"> on a non-loopback address.</summary>
/// <summary>Tried to create an <see cref="IPCNetworkInterface" /> on a non-loopback address.</summary>
NetworkArgumentMismatch = -9,

/// <summary>The underlying network socket has failed.</summary>
NetworkSocketError = -10,
}
}

Expand Down
2 changes: 2 additions & 0 deletions Runtime/NetworkDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,8 @@ public bool Equals(Connection connection)
int m_NetworkInterfaceIndex;
NetworkSendInterface m_NetworkSendInterface;

internal INetworkInterface NetworkInterface => s_NetworkInterfaces[m_NetworkInterfaceIndex];

int m_NetworkProtocolIndex;
NetworkProtocol m_NetworkProtocolInterface;

Expand Down
11 changes: 11 additions & 0 deletions Tests/Editor/RelayNetworkDriverTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public void RelayCheckStructSizes()
}

[Test]
[UnityPlatform(exclude = new[] { RuntimePlatform.OSXEditor, RuntimePlatform.OSXPlayer })] // MTT-3864
[Ignore("Unstable in APVs. See MTT-4345.")]
public void RelayNetworkDriver_Bind_Succeed()
{
using var server = new RelayServerMock("127.0.0.1", m_port++);
Expand All @@ -46,6 +48,8 @@ public void RelayNetworkDriver_Bind_Succeed()
}

[Test]
[UnityPlatform(exclude = new[] { RuntimePlatform.OSXEditor, RuntimePlatform.OSXPlayer })] // MTT-3864
[Ignore("Unstable in APVs. See MTT-4345.")]
public void RelayNetworkDriver_Bind_Retry()
{
const int k_RetryCount = 10;
Expand Down Expand Up @@ -80,6 +84,7 @@ public void RelayNetworkDriver_Bind_Retry()
}

[Test]
[UnityPlatform(exclude = new[] { RuntimePlatform.OSXEditor, RuntimePlatform.OSXPlayer })] // MTT-3864
public void RelayNetworkDriver_Bind_Fail()
{
using var server = new RelayServerMock("127.0.0.1", m_port++);
Expand Down Expand Up @@ -113,6 +118,7 @@ public void RelayNetworkDriver_Bind_Fail()
}

[Test]
[UnityPlatform(exclude = new[] { RuntimePlatform.OSXEditor, RuntimePlatform.OSXPlayer })] // MTT-3864
public void RelayNetworkDriver_Listen_Succeed()
{
using var server = new RelayServerMock("127.0.0.1", m_port++);
Expand All @@ -129,6 +135,7 @@ public void RelayNetworkDriver_Listen_Succeed()
}

[Test]
[UnityPlatform(exclude = new[] { RuntimePlatform.OSXEditor, RuntimePlatform.OSXPlayer })] // MTT-3864
public void RelayNetworkDriver_Connect_Succeed()
{
using var server = new RelayServerMock("127.0.0.1", m_port++);
Expand Down Expand Up @@ -177,6 +184,7 @@ public void RelayNetworkDriver_Connect_Succeed()
}

[Test]
[UnityPlatform(exclude = new[] { RuntimePlatform.OSXEditor, RuntimePlatform.OSXPlayer })] // MTT-3864
public void RelayNetworkDriver_Connect_Retry()
{
const int k_RetryCount = 10;
Expand Down Expand Up @@ -231,6 +239,7 @@ public void RelayNetworkDriver_Connect_Retry()
}

[Test]
[UnityPlatform(exclude = new[] { RuntimePlatform.OSXEditor, RuntimePlatform.OSXPlayer })] // MTT-3864
public void RelayNetworkDriver_Disconnect_Succeed()
{
using var server = new RelayServerMock("127.0.0.1", m_port++);
Expand Down Expand Up @@ -278,6 +287,7 @@ public void RelayNetworkDriver_Disconnect_Succeed()
}

[Test]
[UnityPlatform(exclude = new[] { RuntimePlatform.OSXEditor, RuntimePlatform.OSXPlayer })] // MTT-3864
public void RelayNetworkDriver_Send_Succeed()
{
const int k_PayloadSize = 100;
Expand Down Expand Up @@ -323,6 +333,7 @@ public void RelayNetworkDriver_Send_Succeed()
}

[Test]
[UnityPlatform(exclude = new[] { RuntimePlatform.OSXEditor, RuntimePlatform.OSXPlayer })] // MTT-3864
public void RelayNetworkDriver_AllocationTimeOut()
{
using var server = new RelayServerMock("127.0.0.1", m_port++);
Expand Down
76 changes: 61 additions & 15 deletions Tests/Runtime/BaselibNetworkInterfaceTests.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.Threading;
using NUnit.Framework;
using Unity.Networking.Transport;
using Unity.Networking.Transport.Utilities;
using UnityEngine;
using UnityEngine.TestTools;
using System.Linq;
Expand Down Expand Up @@ -49,9 +48,15 @@ public unsafe void Baselib_Send_WaitForCompletion()
}
}

private void FakeSocketFailure(BaselibNetworkInterface baselibInterface)
{
var baselib = baselibInterface.m_Baselib[0];
baselib.m_SocketStatus = BaselibNetworkInterface.SocketStatus.SocketNeedsRecreate;
baselibInterface.m_Baselib[0] = baselib;
}

[Test]
[UnityPlatform(include = new[] { RuntimePlatform.IPhonePlayer })]
public void Baselib_AfterAppSuspension_SocketIsRecreated()
public void Baselib_AfterSocketFailure_SocketIsRecreated()
{
using (var baselibInterface = new BaselibNetworkInterface())
using (var dummyDriver = NetworkDriver.Create())
Expand All @@ -69,34 +74,75 @@ public void Baselib_AfterAppSuspension_SocketIsRecreated()
packetReceiver.m_Driver = dummyDriver;
baselibInterface.ScheduleReceive(packetReceiver, default).Complete();

// Fake an app suspension by manually calling the focus callback. We add sleeps
// around the call to ensure the timestamp is different from the receice jobs.
Thread.Sleep(5);
AppForegroundTracker.OnFocusChanged(true);
Thread.Sleep(5);
// Sleep to ensure different update times.
Thread.Sleep(2);

FakeSocketFailure(baselibInterface);

dummyDriver.ScheduleUpdate().Complete();
packetReceiver.m_Driver = dummyDriver;
baselibInterface.ScheduleReceive(packetReceiver, default).Complete();

Assert.AreNotEqual(socket, baselibInterface.m_Baselib[0].m_Socket);

LogAssert.Expect(LogType.Warning, "Socket error encountered; attempting recovery by creating a new one.");
}
}

[Test]
public void Baselib_AfterBackToBackSocketFailures_SocketIsFailed()
{
using (var baselibInterface = new BaselibNetworkInterface())
using (var dummyDriver = NetworkDriver.Create())
{
var settings = new NetworkSettings();
baselibInterface.Initialize(settings);
baselibInterface.CreateInterfaceEndPoint(NetworkEndPoint.AnyIpv4, out var endpoint);
Assert.Zero(baselibInterface.Bind(endpoint));

var packetReceiver = new NetworkPacketReceiver();

dummyDriver.ScheduleUpdate().Complete();
packetReceiver.m_Driver = dummyDriver;
baselibInterface.ScheduleReceive(packetReceiver, default).Complete();

// Sleep to ensure different update times.
Thread.Sleep(2);

FakeSocketFailure(baselibInterface);

dummyDriver.ScheduleUpdate().Complete();
packetReceiver.m_Driver = dummyDriver;
baselibInterface.ScheduleReceive(packetReceiver, default).Complete();

LogAssert.Expect(LogType.Warning, "Socket error encountered; attempting recovery by creating a new one.");

// Sleep to ensure different update times.
Thread.Sleep(2);

FakeSocketFailure(baselibInterface);

dummyDriver.ScheduleUpdate().Complete();
packetReceiver.m_Driver = dummyDriver;
baselibInterface.ScheduleReceive(packetReceiver, default).Complete();

Assert.AreEqual((int)Error.StatusCode.NetworkSocketError, dummyDriver.ReceiveErrorCode);

LogAssert.Expect(LogType.Error, "Unrecoverable socket failure. An unknown condition is preventing the application from reliably creating sockets.");
LogAssert.Expect(LogType.Error, "Error on receive, errorCode = -10");
}
}

[Test]
[UnityPlatform(include = new[] { RuntimePlatform.IPhonePlayer })]
public void Baselib_AfterAppSuspension_CanSendReceive()
public void Baselib_AfterSocketRecreation_CanSendReceive()
{
using (var server = NetworkDriver.Create())
using (var client = NetworkDriver.Create())
{
ConnectServerAndClient(NetworkEndPoint.LoopbackIpv4, server, client, out _, out var connection);

// Fake an app suspension by manually calling the focus callback. We add sleeps
// around the call to ensure the timestamp is different from the driver updates.
Thread.Sleep(5);
AppForegroundTracker.OnFocusChanged(true);
Thread.Sleep(5);
var clientBaselibInterface = (BaselibNetworkInterface)client.NetworkInterface;
FakeSocketFailure(clientBaselibInterface);

// Let the server and client recreate their sockets.
client.ScheduleUpdate().Complete();
Expand Down
1 change: 1 addition & 0 deletions Tests/Runtime/ConnectDisconnectTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public void ConnectDisconnect_MultipleClients(
}

[Test]
[Ignore("Unstable in APVs. See MTT-4345.")]
public void ConnectDisconnect_ConnectSucceedsAfterRetrying(
[ValueSource("s_SecureModeParameters")] SecureProtocolMode secureMode)
{
Expand Down
1 change: 1 addition & 0 deletions Tests/Runtime/DisconnectTimeoutTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public void DisconnectTimeout_ReachedWithInfrequentHeartbeats()
}

[Test]
[Ignore("Unstable in APVs. See MTT-4345.")]
public void DisconnectTimeout_NotReachedWithFrequentHeartbeats()
{
var settings = new NetworkSettings();
Expand Down
1 change: 1 addition & 0 deletions Tests/Runtime/SendMessageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ public void SendMessage_PingPong_MaxLength(
}

[UnityTest, UnityPlatform(RuntimePlatform.LinuxEditor, RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor)]
[Ignore("Unstable in APVs. See MTT-4345.")]
public IEnumerator SendMessage_OverflowedReceiveBuffer()
{
var settings = new NetworkSettings();
Expand Down
4 changes: 2 additions & 2 deletions ValidationExceptions.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
{
"ValidationTest": "Restricted File Type Validation",
"ExceptionMessage": "/Samples~/CustomNetworkInterface/Scripts/network.bindings~/build.bat cannot be included in a package.",
"PackageVersion": "1.1.0"
"PackageVersion": "1.2.0"
},
{
"ValidationTest": "Restricted File Type Validation",
"ExceptionMessage": "/Samples~/CustomNetworkInterface/Scripts/network.bindings~/shell.bat cannot be included in a package.",
"PackageVersion": "1.1.0"
"PackageVersion": "1.2.0"
}
],
"WarningExceptions": []
Expand Down
9 changes: 3 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "com.unity.transport",
"displayName": "Unity Transport",
"version": "1.1.0",
"version": "1.2.0",
"unity": "2020.3",
"unityRelease": "0f1",
"description": "Unity network transport layer - the low-level interface for sending UDP data",
Expand All @@ -10,16 +10,13 @@
"com.unity.burst": "1.6.6",
"com.unity.mathematics": "1.2.6"
},
"_upm": {
"changelog": "### New features\n* A `DataStreamReader` can now be passed to another job without triggering the job safety system.\n* A `GetRelayConnectionStatus` method has been added to `NetworkDriver` to query the status of the connection to the Relay server.\n\n### Changes\n* `NetworkSettings.WithDataStreamParameters` is now obsolete. The functionality still works and will remain supported for version 1.X of the package, but will be removed in version 2.0. The reason for the removal is that in 2.0 the data stream size is always dynamically-sized to avoid out-of-memory errors.\n* `NetworkSettings.WithPipelineParameters` is now obsolete. The functionality still works and will remain supported for version 1.X of the package, but will be removed in version 2.0, where pipeline buffer sizing is handled internally.\n* Updated Burst dependency to 1.6.6.\n* Updated Collections dependency to 1.2.4.\n* Updated Mathematics dependency to 1.2.6.\n\n### Fixes\n* `BeginSend` would not return an error if called on a closed connection before the next `ScheduleUpdate` call.\n* Fixed a warning if using the default maximum payload size with DTLS.\n* Removed an error log when receiving messages on a closed DTLS connection (this scenario is common if there were in-flight messages at the moment of disconnection).\n* Fix broken link in package documentation."
},
"upmCi": {
"footprint": "cd3960b74c34568953deb592a44e23402c3a914c"
"footprint": "b86aef366145fa59d88b43f35ef32b38cf576ef6"
},
"repository": {
"url": "https://github.cds.internal.unity3d.com/unity/com.unity.transport.git",
"type": "git",
"revision": "ce258b46039e4d4937778aa8d02c6532b9ea0888"
"revision": "b4fadab8f255b0b13f371bea8d2819c2ca472648"
},
"samples": [
{
Expand Down

0 comments on commit 2eca5b0

Please sign in to comment.