multiplayer-community-contributions
multiplayer-community-contributions copied to clipboard
Websocket Connect to URL instead of IP
I'm having trouble configuring websockets using a URL instead of an IP address. It works fine when using the IP address and I've confirmed the port is open and the websocket server is accepting incomming connections. (Replaced my real URL with example.io just for this post)
Maybe this is something that is not currently supported but I can't imagine it would be too difficult to implement.
Invalid network endpoint: example.io:7777.
UnityEngine.Debug:LogError (object)
Unity.Netcode.Transports.UTP.UnityTransport/ConnectionAddressData:ParseNetworkEndpoint (string,uint16) (at Library/PackageCache/[email protected]/Runtime/Transports/UTP/UnityTransport.cs:319)
Unity.Netcode.Transports.UTP.UnityTransport/ConnectionAddressData:get_ServerEndPoint () (at Library/PackageCache/[email protected]/Runtime/Transports/UTP/UnityTransport.cs:328)
Unity.Netcode.Transports.UTP.UnityTransport:ClientBindAndConnect () (at Library/PackageCache/[email protected]/Runtime/Transports/UTP/UnityTransport.cs:506)
Unity.Netcode.Transports.UTP.UnityTransport:StartClient () (at Library/PackageCache/[email protected]/Runtime/Transports/UTP/UnityTransport.cs:1282)
Unity.Netcode.NetworkManager:StartClient () (at Library/PackageCache/[email protected]/Runtime/Core/NetworkManager.cs:1104)
Unity.Netcode.Samples.BootstrapManager:OnGUI () (at Assets/Samples/Netcode for GameObjects/1.2.0/Bootstrap/Scripts/BootstrapManager.cs:26)
This is the function throwing the exception.
private static NetworkEndpoint ParseNetworkEndpoint(string ip, ushort port)
{
NetworkEndpoint endpoint = default;
if (!NetworkEndpoint.TryParse(ip, port, out endpoint, NetworkFamily.Ipv4) &&
!NetworkEndpoint.TryParse(ip, port, out endpoint, NetworkFamily.Ipv6))
{
Debug.LogError($"Invalid network endpoint: {ip}:{port}.");
}
return endpoint;
}
Connection works when I use SSL Encryption and set the URL as ServerCommonName 👍
var networkManager = NetworkManager.Singleton;
m_Transport = (UnityTransport)m_NetworkManager.NetworkConfig.NetworkTransport;
m_Transport.SetServerSecrets(MyGameServerCertificate, MyGameServerPrivateKey);
networkManager.StartServer();
m_Transport.SetClientSecrets(ServerCommonName, MyGameClientCA);
networkManager.StartClient();
However, now I am running into a new issue.
The first client connects perfectly fine, but when a second client trys to connect the first client is kicked from the game and the second client recieves a failed to connect error. When the second client attempts to connect again it works the second time.
Server shows this error:
TLS handshake failed at step 8. Closing connection.
0x00007ff792cfe58a (Unity) DefaultBurstRuntimeLogCallback
0x00007ff7923f17ba (Unity) BurstCompilerService_CUSTOM_RuntimeLog
0x00007ffbfdbeb472 (c5d232c9cae857190c1d09f2492afd3) Unity.Networking.Transport.TLSLayer/ReceiveJob::Unity.Networking.Transport.TLSLayer.ReceiveJob.CheckForFailedClient (at C:/Users/Davey/Documents/OffTheRails-v2/Library/PackageCache/[email protected]/Runtime/Layers/TLSLayer.cs:417)
0x00007ffbfdbecf9a (c5d232c9cae857190c1d09f2492afd3) Unity.Networking.Transport.TLSLayer/ReceiveJob::Unity.Networking.Transport.TLSLayer.ReceiveJob.ProcessConnectionList (at C:/Users/Davey/Documents/OffTheRails-v2/Library/PackageCache/[email protected]/Runtime/Layers/TLSLayer.cs:321)
0x00007ffbfdbea101 (c5d232c9cae857190c1d09f2492afd3) a3be22cf2efbecd470a3a9efab4602bf
0x00007ff792fda620 (Unity) ExecuteJob
0x00007ff792fdb9ff (Unity) ForwardJobToManaged
0x00007ff792fd82b4 (Unity) ujob_execute_job
0x00007ff792fd79c7 (Unity) lane_guts
0x00007ff792fd9874 (Unity) worker_thread_routine
0x00007ff7931f0d97 (Unity) Thread::RunThreadWrapper
0x00007ffc35977614 (KERNEL32) BaseThreadInitThunk
0x00007ffc373e26a1 (ntdll) RtlUserThreadStart
And these warnings:
Received message with invalid reserved header bits
0x00007ff792cfe58a (Unity) DefaultBurstRuntimeLogCallback
0x00007ff7923f17ba (Unity) BurstCompilerService_CUSTOM_RuntimeLog
0x00007ffbfdbbb9d0 (c5d232c9cae857190c1d09f2492afd3) Unity.Networking.Transport.WebSocketLayer/ReceiveJob::Unity.Networking.Transport.WebSocketLayer.ReceiveJob.ProcessWebSocketFrames (at C:/Users/Davey/Documents/OffTheRails-v2/Library/PackageCache/[email protected]/Runtime/Layers/WebSocketLayer.cs:586)
0x00007ffbfdbba689 (c5d232c9cae857190c1d09f2492afd3) Unity.Networking.Transport.WebSocketLayer/ReceiveJob::Unity.Networking.Transport.WebSocketLayer.ReceiveJob.ProcessReceivedMessages (at C:/Users/Davey/Documents/OffTheRails-v2/Library/PackageCache/[email protected]/Runtime/Layers/WebSocketLayer.cs:525)
0x00007ffbfdbadb2d (c5d232c9cae857190c1d09f2492afd3) Unity.Jobs.IJobExtensions.JobStruct`1<Unity.Networking.Transport.WebSocketLayer.ReceiveJob>.Execute (at C:/Users/Davey/Documents/OffTheRails-v2/unknown/unknown:0)
0x00007ffbfdba9e31 (c5d232c9cae857190c1d09f2492afd3) ce7051e47e4dcf1c405534050a172262
0x00007ff792fda620 (Unity) ExecuteJob
0x00007ff792fdb9ff (Unity) ForwardJobToManaged
0x00007ff792fd82b4 (Unity) ujob_execute_job
0x00007ff792fd79c7 (Unity) lane_guts
0x00007ff792fd9874 (Unity) worker_thread_routine
0x00007ff7931f0d97 (Unity) Thread::RunThreadWrapper
0x00007ffc35977614 (KERNEL32) BaseThreadInitThunk
0x00007ffc373e26a1 (ntdll) RtlUserThreadStart
Received message with unexpected masking
0x00007ff792cfe58a (Unity) DefaultBurstRuntimeLogCallback
0x00007ff7923f17ba (Unity) BurstCompilerService_CUSTOM_RuntimeLog
0x00007ffbfdbbba0a (c5d232c9cae857190c1d09f2492afd3) Unity.Networking.Transport.WebSocketLayer/ReceiveJob::Unity.Networking.Transport.WebSocketLayer.ReceiveJob.ProcessWebSocketFrames (at C:/Users/Davey/Documents/OffTheRails-v2/Library/PackageCache/[email protected]/Runtime/Layers/WebSocketLayer.cs:587)
0x00007ffbfdbba689 (c5d232c9cae857190c1d09f2492afd3) Unity.Networking.Transport.WebSocketLayer/ReceiveJob::Unity.Networking.Transport.WebSocketLayer.ReceiveJob.ProcessReceivedMessages (at C:/Users/Davey/Documents/OffTheRails-v2/Library/PackageCache/[email protected]/Runtime/Layers/WebSocketLayer.cs:525)
0x00007ffbfdbadb2d (c5d232c9cae857190c1d09f2492afd3) Unity.Jobs.IJobExtensions.JobStruct`1<Unity.Networking.Transport.WebSocketLayer.ReceiveJob>.Execute (at C:/Users/Davey/Documents/OffTheRails-v2/unknown/unknown:0)
0x00007ffbfdba9e31 (c5d232c9cae857190c1d09f2492afd3) ce7051e47e4dcf1c405534050a172262
0x00007ff792fda620 (Unity) ExecuteJob
0x00007ff792fdb9ff (Unity) ForwardJobToManaged
0x00007ff792fd82b4 (Unity) ujob_execute_job
0x00007ff792fd79c7 (Unity) lane_guts
0x00007ff792fd9874 (Unity) worker_thread_routine
0x00007ff7931f0d97 (Unity) Thread::RunThreadWrapper
0x00007ffc35977614 (KERNEL32) BaseThreadInitThunk
0x00007ffc373e26a1 (ntdll) RtlUserThreadStart
Received a fragmented control frame.
0x00007ff792cfe58a (Unity) DefaultBurstRuntimeLogCallback
0x00007ff7923f17ba (Unity) BurstCompilerService_CUSTOM_RuntimeLog
0x00007ffbfdbbba48 (c5d232c9cae857190c1d09f2492afd3) Unity.Networking.Transport.WebSocketLayer/ReceiveJob::Unity.Networking.Transport.WebSocketLayer.ReceiveJob.ProcessWebSocketFrames (at C:/Users/Davey/Documents/OffTheRails-v2/Library/PackageCache/[email protected]/Runtime/Layers/WebSocketLayer.cs:588)
0x00007ffbfdbba689 (c5d232c9cae857190c1d09f2492afd3) Unity.Networking.Transport.WebSocketLayer/ReceiveJob::Unity.Networking.Transport.WebSocketLayer.ReceiveJob.ProcessReceivedMessages (at C:/Users/Davey/Documents/OffTheRails-v2/Library/PackageCache/[email protected]/Runtime/Layers/WebSocketLayer.cs:525)
0x00007ffbfdbadb2d (c5d232c9cae857190c1d09f2492afd3) Unity.Jobs.IJobExtensions.JobStruct`1<Unity.Networking.Transport.WebSocketLayer.ReceiveJob>.Execute (at C:/Users/Davey/Documents/OffTheRails-v2/unknown/unknown:0)
0x00007ffbfdba9e31 (c5d232c9cae857190c1d09f2492afd3) ce7051e47e4dcf1c405534050a172262
0x00007ff792fda620 (Unity) ExecuteJob
0x00007ff792fdb9ff (Unity) ForwardJobToManaged
0x00007ff792fd82b4 (Unity) ujob_execute_job
0x00007ff792fd79c7 (Unity) lane_guts
0x00007ff792fd9874 (Unity) worker_thread_routine
0x00007ff7931f0d97 (Unity) Thread::RunThreadWrapper
0x00007ffc35977614 (KERNEL32) BaseThreadInitThunk
0x00007ffc373e26a1 (ntdll) RtlUserThreadStart
I am using Unity Editor 2022.2.0b16 with Unity Transport 2.0.0-pre.3 and Websocket Transport 2.0.0 and NGO 1.2.0 The connections are being routed through a Cloudflare proxy. I've also tested with Unity Transport 2.0.0-exp.8 and run into the same issue. Running on port 443.
I find it weird that if the second client connecting recieves a TLS handshake error then why is the first client being kicked? Also this happens 95% of the time but there are a few occasions where both clients can connect simultaniously with no issue.
@Davey111 having the same issue, did you manage to progress?
@ToolKami Partially..
Instead of using the Unity Transport and checking the "Use Web Sockets" box I realized the package contains another transport script called "Web Socket Transport" that entirely replaces the default Unity Transport script.
This allows the use of URLs in the Address box but I still had the TLS handshake error.
My workaround was to run the server unencrypted and use an NGINX reverse SSL proxy to forward unencrypted packets to the server. Unfortuntely its not the prettiest fix but at least its working for me now.
This is how I have my client setup:
Server setup:
Thanks @Davey111 ! I'm fairly new to Unity, will try to spend a little more time to debug with my limited skills, otherwise I'll try your method, do you mind sharing your working nginx.conf
too? 🙏
So far, I've traced the origin of the error TLS handshake failed at step 8. Closing connection.
to [email protected]/Runtime/DebugLog.cs
:
public static void ErrorDTLSHandshakeFailed(uint handshakeStep)
{
#if USE_UNITY_LOGGING
Unity.Logging.Log.Error("DTLS handshake failed at step {HandshakeStep}. Closing connection.", handshakeStep);
#else
UnityEngine.Debug.LogError($"DTLS handshake failed at step {handshakeStep}. Closing connection.");
#endif
}
which is called from [email protected]/Runtime/Layers/DTLSLayer.cs
:
private void CheckForFailedClient(ConnectionId connection)
{
var clientPtr = ConnectionsData[connection].UnityTLSClientPtr;
if (clientPtr == null)
return;
ulong dummy;
var errorState = Binding.unitytls_client_get_errorsState(clientPtr, &dummy);
var clientState = Binding.unitytls_client_get_state(clientPtr);
if (errorState != Binding.UNITYTLS_SUCCESS || clientState == Binding.UnityTLSClientState_Fail)
{
// The only way to get a failed client is because of a failed handshake.
if (clientState == Binding.UnityTLSClientState_Fail)
{
// TODO Would be nice to translate the numerical step in a string.
var handshakeStep = Binding.unitytls_client_get_handshake_state(clientPtr);
DebugLog.ErrorDTLSHandshakeFailed(handshakeStep);
}
Connections.StartDisconnecting(ref connection);
// TODO Not the ideal disconnect reason. If we ever have a better one, use it.
Disconnect(connection, Error.DisconnectReason.ClosedByRemote);
}
}
I agree the TODO
would be nice 😆
Was able to narrow it down in the Unity C# source UnityCsReference/External/unitytls/builds/CSharp/BindingsUnity/TLSAgent.gen.bindings.cs
, but at a dead end without access to the C++ source:
[FreeFunction(IsThreadSafe = true)]
public static extern uint unitytls_client_get_handshake_state(unitytls_client* clientInstance);
/// <summary>Retrieves the last error state reported by unitytls internally.</summary>
/// <remarks>
/// The return value is the unitytls_error_code value and the value written to reserved is the internal implmentation-specific value. In general, reserved is to be
/// ignored in favor of the return value.
/// If client is invalid and/and we would not retrieve these values UNITYTLS_USER_CUSTOM_ERROR_END is returned and
/// reserved left untouched.
/// </remarks>
/// <param name="clientInstance">pointer to the (opaque) client instance</param>
/// <param name="reserved">(out) pointer to an int where the implementation-specific error code value will be written</param>
Thanks @Davey111 ! I'm fairly new to Unity, will try to spend a little more time to debug with my limited skills, otherwise I'll try your method, do you mind sharing your working
nginx.conf
too? 🙏
Sure 😊
server {
server_name example.com;
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://localhost:7777;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-Port $remote_port;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}