Skip to content

Commit bf4788e

Browse files
committed
feat: Added support for event driven transports
1 parent ddaeaf3 commit bf4788e

File tree

2 files changed

+135
-119
lines changed

2 files changed

+135
-119
lines changed

MLAPI/Core/NetworkingManager.cs

Lines changed: 127 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -286,11 +286,6 @@ private void OnValidate()
286286

287287
int playerPrefabCount = NetworkConfig.NetworkedPrefabs.Count(x => x.PlayerPrefab == true);
288288

289-
if (playerPrefabCount == 0)
290-
{
291-
292-
}
293-
294289
if (playerPrefabCount == 0 && !NetworkConfig.ConnectionApproval && NetworkConfig.CreatePlayerPrefab)
295290
{
296291
if (LogHelper.CurrentLogLevel <= LogLevel.Normal) LogHelper.LogWarning("There is no NetworkedPrefab marked as a PlayerPrefab");
@@ -389,6 +384,8 @@ private void Init(bool server)
389384
NetworkConfig.NetworkedPrefabs[i].Prefab.GetComponent<NetworkedObject>().ValidateHash();
390385
}
391386

387+
NetworkConfig.NetworkTransport.OnTransportEvent += HandleRawTransportPoll;
388+
392389
NetworkConfig.NetworkTransport.Init();
393390
}
394391

@@ -604,6 +601,7 @@ private void Shutdown()
604601
IsListening = false;
605602
IsServer = false;
606603
IsClient = false;
604+
NetworkConfig.NetworkTransport.OnTransportEvent -= HandleRawTransportPoll;
607605
SpawnManager.DestroyNonSceneObjects();
608606
SpawnManager.ServerResetShudownStateForSceneObjects();
609607

@@ -628,121 +626,8 @@ private void Update()
628626
{
629627
processedEvents++;
630628
eventType = NetworkConfig.NetworkTransport.PollEvent(out ulong clientId, out string channelName, out ArraySegment<byte> payload, out float receiveTime);
629+
HandleRawTransportPoll(eventType, clientId, channelName, payload, receiveTime);
631630

632-
switch (eventType)
633-
{
634-
case NetEventType.Connect:
635-
NetworkProfiler.StartEvent(TickType.Receive, (uint)payload.Count, channelName, "TRANSPORT_CONNECT");
636-
if (IsServer)
637-
{
638-
if (LogHelper.CurrentLogLevel <= LogLevel.Developer) LogHelper.LogInfo("Client Connected");
639-
#if !DISABLE_CRYPTOGRAPHY
640-
if (NetworkConfig.EnableEncryption)
641-
{
642-
// This client is required to complete the crypto-hail exchange.
643-
using (PooledBitStream hailStream = PooledBitStream.Get())
644-
{
645-
using (PooledBitWriter hailWriter = PooledBitWriter.Get(hailStream))
646-
{
647-
if (NetworkConfig.SignKeyExchange)
648-
{
649-
// Write certificate
650-
hailWriter.WriteByteArray(NetworkConfig.ServerX509CertificateBytes);
651-
}
652-
653-
// Write key exchange public part
654-
EllipticDiffieHellman diffieHellman = new EllipticDiffieHellman(EllipticDiffieHellman.DEFAULT_CURVE, EllipticDiffieHellman.DEFAULT_GENERATOR, EllipticDiffieHellman.DEFAULT_ORDER);
655-
byte[] diffieHellmanPublicPart = diffieHellman.GetPublicKey();
656-
hailWriter.WriteByteArray(diffieHellmanPublicPart);
657-
PendingClients.Add(clientId, new PendingClient()
658-
{
659-
ClientId = clientId,
660-
ConnectionState = PendingClient.State.PendingHail,
661-
KeyExchange = diffieHellman
662-
});
663-
664-
if (NetworkConfig.SignKeyExchange)
665-
{
666-
// Write public part signature (signed by certificate private)
667-
X509Certificate2 certificate = NetworkConfig.ServerX509Certificate;
668-
if (!certificate.HasPrivateKey) throw new CryptographicException("[MLAPI] No private key was found in server certificate. Unable to sign key exchange");
669-
670-
RSACryptoServiceProvider rsa = certificate.PrivateKey as RSACryptoServiceProvider;
671-
DSACryptoServiceProvider dsa = certificate.PrivateKey as DSACryptoServiceProvider;
672-
673-
if (rsa != null)
674-
{
675-
// RSA is 0
676-
hailWriter.WriteByte(0);
677-
678-
using (SHA256Managed sha = new SHA256Managed())
679-
{
680-
hailWriter.WriteByteArray(rsa.SignData(diffieHellmanPublicPart, sha));
681-
}
682-
}
683-
else if (dsa != null)
684-
{
685-
// DSA is 1
686-
hailWriter.WriteByte(1);
687-
688-
using (SHA256Managed sha = new SHA256Managed())
689-
{
690-
hailWriter.WriteByteArray(dsa.SignData(sha.ComputeHash(diffieHellmanPublicPart)));
691-
}
692-
}
693-
else
694-
{
695-
throw new CryptographicException("[MLAPI] Only RSA and DSA certificates are supported. No valid RSA or DSA key was found");
696-
}
697-
}
698-
}
699-
// Send the hail
700-
InternalMessageSender.Send(clientId, MLAPIConstants.MLAPI_CERTIFICATE_HAIL, "MLAPI_INTERNAL", hailStream, SecuritySendFlags.None, null);
701-
}
702-
}
703-
else
704-
{
705-
#endif
706-
PendingClients.Add(clientId, new PendingClient()
707-
{
708-
ClientId = clientId,
709-
ConnectionState = PendingClient.State.PendingConnection
710-
});
711-
#if !DISABLE_CRYPTOGRAPHY
712-
}
713-
#endif
714-
StartCoroutine(ApprovalTimeout(clientId));
715-
}
716-
else
717-
{
718-
if (LogHelper.CurrentLogLevel <= LogLevel.Developer) LogHelper.LogInfo("Connected");
719-
if (!NetworkConfig.EnableEncryption) SendConnectionRequest();
720-
StartCoroutine(ApprovalTimeout(clientId));
721-
}
722-
NetworkProfiler.EndEvent();
723-
break;
724-
case NetEventType.Data:
725-
if (LogHelper.CurrentLogLevel <= LogLevel.Developer) LogHelper.LogInfo($"Incoming Data From {clientId} : {payload.Count} bytes");
726-
727-
HandleIncomingData(clientId, channelName, payload, receiveTime);
728-
break;
729-
case NetEventType.Disconnect:
730-
NetworkProfiler.StartEvent(TickType.Receive, 0, "NONE", "TRANSPORT_DISCONNECT");
731-
if (LogHelper.CurrentLogLevel <= LogLevel.Developer) LogHelper.LogInfo("Disconnect Event From " + clientId);
732-
733-
if (IsServer)
734-
OnClientDisconnectFromServer(clientId);
735-
else
736-
{
737-
IsConnectedClient = false;
738-
StopClient();
739-
}
740-
741-
if (OnClientDisconnectCallback != null)
742-
OnClientDisconnectCallback.Invoke(clientId);
743-
NetworkProfiler.EndEvent();
744-
break;
745-
}
746631
// Only do another iteration if: there are no more messages AND (there is no limit to max events or we have processed less than the maximum)
747632
} while (IsListening && (eventType != NetEventType.Nothing && (NetworkConfig.MaxReceiveEventsPerTickRate <= 0 || processedEvents < NetworkConfig.MaxReceiveEventsPerTickRate)));
748633
lastReceiveTickTime = NetworkTime;
@@ -843,6 +728,129 @@ internal IEnumerator TimeOutSwitchSceneProgress(SceneSwitchProgress switchSceneP
843728
switchSceneProgress.SetTimedOut();
844729
}
845730

731+
private void HandleRawTransportPoll(NetEventType eventType, ulong clientId, string channelName, ArraySegment<byte> payload, float receiveTime)
732+
{
733+
switch (eventType)
734+
{
735+
case NetEventType.Connect:
736+
NetworkProfiler.StartEvent(TickType.Receive, (uint)payload.Count, channelName, "TRANSPORT_CONNECT");
737+
if (IsServer)
738+
{
739+
if (LogHelper.CurrentLogLevel <= LogLevel.Developer) LogHelper.LogInfo("Client Connected");
740+
#if !DISABLE_CRYPTOGRAPHY
741+
if (NetworkConfig.EnableEncryption)
742+
{
743+
// This client is required to complete the crypto-hail exchange.
744+
using (PooledBitStream hailStream = PooledBitStream.Get())
745+
{
746+
using (PooledBitWriter hailWriter = PooledBitWriter.Get(hailStream))
747+
{
748+
if (NetworkConfig.SignKeyExchange)
749+
{
750+
// Write certificate
751+
hailWriter.WriteByteArray(NetworkConfig.ServerX509CertificateBytes);
752+
}
753+
754+
// Write key exchange public part
755+
EllipticDiffieHellman diffieHellman = new EllipticDiffieHellman(EllipticDiffieHellman.DEFAULT_CURVE, EllipticDiffieHellman.DEFAULT_GENERATOR, EllipticDiffieHellman.DEFAULT_ORDER);
756+
byte[] diffieHellmanPublicPart = diffieHellman.GetPublicKey();
757+
hailWriter.WriteByteArray(diffieHellmanPublicPart);
758+
PendingClients.Add(clientId, new PendingClient()
759+
{
760+
ClientId = clientId,
761+
ConnectionState = PendingClient.State.PendingHail,
762+
KeyExchange = diffieHellman
763+
});
764+
765+
if (NetworkConfig.SignKeyExchange)
766+
{
767+
// Write public part signature (signed by certificate private)
768+
X509Certificate2 certificate = NetworkConfig.ServerX509Certificate;
769+
770+
if (!certificate.HasPrivateKey)
771+
throw new CryptographicException("[MLAPI] No private key was found in server certificate. Unable to sign key exchange");
772+
773+
RSACryptoServiceProvider rsa = certificate.PrivateKey as RSACryptoServiceProvider;
774+
DSACryptoServiceProvider dsa = certificate.PrivateKey as DSACryptoServiceProvider;
775+
776+
if (rsa != null)
777+
{
778+
// RSA is 0
779+
hailWriter.WriteByte(0);
780+
781+
using (SHA256Managed sha = new SHA256Managed())
782+
{
783+
hailWriter.WriteByteArray(rsa.SignData(diffieHellmanPublicPart, sha));
784+
}
785+
}
786+
else if (dsa != null)
787+
{
788+
// DSA is 1
789+
hailWriter.WriteByte(1);
790+
791+
using (SHA256Managed sha = new SHA256Managed())
792+
{
793+
hailWriter.WriteByteArray(dsa.SignData(sha.ComputeHash(diffieHellmanPublicPart)));
794+
}
795+
}
796+
else
797+
{
798+
throw new CryptographicException("[MLAPI] Only RSA and DSA certificates are supported. No valid RSA or DSA key was found");
799+
}
800+
}
801+
}
802+
// Send the hail
803+
InternalMessageSender.Send(clientId, MLAPIConstants.MLAPI_CERTIFICATE_HAIL, "MLAPI_INTERNAL", hailStream, SecuritySendFlags.None, null);
804+
}
805+
}
806+
else
807+
{
808+
#endif
809+
PendingClients.Add(clientId, new PendingClient()
810+
{
811+
ClientId = clientId,
812+
ConnectionState = PendingClient.State.PendingConnection
813+
});
814+
#if !DISABLE_CRYPTOGRAPHY
815+
}
816+
#endif
817+
StartCoroutine(ApprovalTimeout(clientId));
818+
}
819+
else
820+
{
821+
if (LogHelper.CurrentLogLevel <= LogLevel.Developer) LogHelper.LogInfo("Connected");
822+
823+
if (!NetworkConfig.EnableEncryption)
824+
SendConnectionRequest();
825+
StartCoroutine(ApprovalTimeout(clientId));
826+
}
827+
NetworkProfiler.EndEvent();
828+
break;
829+
case NetEventType.Data:
830+
if (LogHelper.CurrentLogLevel <= LogLevel.Developer) LogHelper.LogInfo($"Incoming Data From {clientId} : {payload.Count} bytes");
831+
832+
HandleIncomingData(clientId, channelName, payload, receiveTime);
833+
break;
834+
case NetEventType.Disconnect:
835+
NetworkProfiler.StartEvent(TickType.Receive, 0, "NONE", "TRANSPORT_DISCONNECT");
836+
837+
if (LogHelper.CurrentLogLevel <= LogLevel.Developer) LogHelper.LogInfo("Disconnect Event From " + clientId);
838+
839+
if (IsServer)
840+
OnClientDisconnectFromServer(clientId);
841+
else
842+
{
843+
IsConnectedClient = false;
844+
StopClient();
845+
}
846+
847+
if (OnClientDisconnectCallback != null)
848+
OnClientDisconnectCallback.Invoke(clientId);
849+
NetworkProfiler.EndEvent();
850+
break;
851+
}
852+
}
853+
846854
private void HandleIncomingData(ulong clientId, string channelName, ArraySegment<byte> data, float receiveTime)
847855
{
848856
if (LogHelper.CurrentLogLevel <= LogLevel.Developer) LogHelper.LogInfo("Unwrapping Data Header");

MLAPI/Transports/Transport.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ public abstract class Transport : MonoBehaviour
6464
}
6565
};
6666

67+
public delegate void TransportEventDelegate(NetEventType type, ulong clientId, string channelName, ArraySegment<byte> payload, float receiveTime);
68+
69+
/// <summary>
70+
/// Occurs when the transport has a new transport event. Can be used to make an event based transport instead of a poll based.
71+
/// Invokation has to occur on the Unity thread in the Update loop.
72+
/// </summary>
73+
public event TransportEventDelegate OnTransportEvent;
74+
6775
/// <summary>
6876
/// Send a payload to the specified clientId, data and channelName.
6977
/// </summary>

0 commit comments

Comments
 (0)