-
Notifications
You must be signed in to change notification settings - Fork 446
fix: client not approved timeout exception #2466
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: client not approved timeout exception #2466
Conversation
Added tracking time out coroutines in order to stop them once a client is either approved or not but has not timed out. Also only disconnecting a client that has timed out and but not disconnecting them if they were not approved (with the coroutine tracking it would be a very edge case scenario).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! 🚀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this changes the flow — I'll give it a second thought.
Please do. Would like to have another set of eyes on this. |
DisconnectClient(clientId); | ||
// Only disconnect when the connection times out. | ||
// If the connection is not approved it will automatically disconnect the client | ||
if (timedOut) | ||
{ | ||
DisconnectClient(clientId); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First, I'd like to quote your (@NoelStephensUnity) comment inline here (for the discussion):
With other transports the removal of client id mapping can happen immediately (server side) when the client is not approved yet the coroutine is left running. Upon timing out (a non-approved server-side client time out coroutine), the server then attempts to disconnect the client which ends up throwing an exception. This doesn't happen with UnityTransport (currently) so this PR is to just to track the coroutines and end them when the client or the server side have received some form of approval response.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also quoting an exception from the linked issue (#2389):
System.Collections.Generic.Dictionary`2[TKey,TValue].get_Item (TKey key) (at <d6232873609549b8a045fa15811a5bd3>:0) Unity.Netcode.NetworkManager.ClientIdToTransportId (System.UInt64 clientId) (at Library/PackageCache/[email protected]/Runtime/Core/NetworkManager.cs:1781) Unity.Netcode.NetworkManager.DisconnectRemoteClient (System.UInt64 clientId) (at Library/PackageCache/[email protected]/Runtime/Core/NetworkManager.cs:1361) Unity.Netcode.NetworkManager.DisconnectClient (System.UInt64 clientId, System.String reason) (at Library/PackageCache/[email protected]/Runtime/Core/NetworkManager.cs:2063) Unity.Netcode.NetworkManager.DisconnectClient (System.UInt64 clientId) (at Library/PackageCache/[email protected]/Runtime/Core/NetworkManager.cs:2038) Unity.Netcode.NetworkManager+<ApprovalTimeout>d__180.MoveNext () (at Library/PackageCache/[email protected]/Runtime/Core/NetworkManager.cs:1765) UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at <bae255e3e08e46f7bc2fbd23dde96338>:0)```
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should not change the behavior here — the minimum fix is to simply handle NM.DisconnectClient()
call gracefully and leave other issues/exceptions related to transport, including 3rd-party ones, up their own implementation.
As a rule of thumb, a transport should be able to handle a disconnect or a send message call to an unknown or "just-removed" connection gracefully.
Perhaps this would give the general idea:
internal ulong TransportIdToClientId(ulong transportId)
{
- return transportId == m_ServerTransportId ? ServerClientId : m_TransportIdToClientIdMap[transportId];
+ if (transportId == m_ServerTransportId)
+ {
+ return ServerClientId;
+ }
+
+ if (m_TransportIdToClientIdMap.TryGetValue(transportId, out var clientId))
+ {
+ return clientId;
+ }
+
+ return default;
}
internal ulong ClientIdToTransportId(ulong clientId)
{
- return clientId == ServerClientId ? m_ServerTransportId : m_ClientIdToTransportIdMap[clientId];
+ if (clientId == ServerClientId)
+ {
+ return m_ServerTransportId;
+ }
+
+ if (m_ClientIdToTransportIdMap.TryGetValue(clientId, out var transportId))
+ {
+ return transportId;
+ }
+
+ return default;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, not sure why I approached it this way.
Fixing the transport id mapping is indeed a less intrusive fix for the issue.
Added the suggested changes to #2475 and closing this PR. |
If connection approval is enabled and a client is not approved, on transports other than UnityTransport the server could throw an exception after the time out coroutine stopped. Additionally, timeout coroutines were not being stopped upon a client being approved or not approved. This PR fixes these minor issues with tests.
Based on #2389 discovery that some third party NetworkTransport implementations might immediately invoke a disconnect network event.
Changelog
Testing and Documentation