예제 #1
0
        internal static void HandleClientRPCRequest(ulong clientId, Stream stream, string channelName, SecuritySendFlags security, Action <ulong> bufferCallback)
        {
            using (PooledBitReader reader = PooledBitReader.Get(stream))
            {
                ulong  networkId   = reader.ReadUInt64Packed();
                ushort behaviourId = reader.ReadUInt16Packed();
                ulong  hash        = reader.ReadUInt64Packed();
                ulong  responseId  = reader.ReadUInt64Packed();

                if (SpawnManager.SpawnedObjects.ContainsKey(networkId))
                {
                    NetworkedBehaviour behaviour = SpawnManager.SpawnedObjects[networkId].GetBehaviourAtOrderIndex(behaviourId);

                    if (behaviour == null)
                    {
                        if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                        {
                            LogHelper.LogWarning("ClientRPCRequest message recieved for a non existant behaviour. NetworkId: " + networkId + ", behaviourIndex: " + behaviourId);
                        }
                    }
                    else
                    {
                        object result = behaviour.OnRemoteClientRPC(hash, clientId, stream);

                        using (PooledBitStream responseStream = PooledBitStream.Get())
                        {
                            using (PooledBitWriter responseWriter = PooledBitWriter.Get(responseStream))
                            {
                                responseWriter.WriteUInt64Packed(responseId);
                                responseWriter.WriteObjectPacked(result);
                            }

                            InternalMessageSender.Send(clientId, MLAPIConstants.MLAPI_CLIENT_RPC_RESPONSE, channelName, responseStream, security, null);
                        }
                    }
                }
                else if (NetworkingManager.Singleton.IsServer || !NetworkingManager.Singleton.NetworkConfig.EnableMessageBuffering)
                {
                    if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                    {
                        LogHelper.LogWarning("ClientRPCRequest message recieved for a non existant object with id: " + networkId + ". This message is lost.");
                    }
                }
                else
                {
                    if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                    {
                        LogHelper.LogWarning("ClientRPCRequest message recieved for a non existant object with id: " + networkId + ". This message will be buffered and might be recovered.");
                    }
                    bufferCallback(networkId);
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Sends unnamed message to a list of clients
        /// </summary>
        /// <param name="clientIds">The clients to send to, sends to everyone if null</param>
        /// <param name="stream">The message stream containing the data</param>
        /// <param name="channel">The channel to send the data on</param>
        /// <param name="security">The security settings to apply to the message</param>
        public static void SendUnnamedMessage(List <ulong> clientIds, BitStream stream, string channel = null, SecuritySendFlags security = SecuritySendFlags.None)
        {
            if (!NetworkingManager.Singleton.IsServer)
            {
                if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                {
                    NetworkLog.LogWarning("Can not send unnamed messages to multiple users as a client");
                }
                return;
            }

            InternalMessageSender.Send(MLAPIConstants.MLAPI_UNNAMED_MESSAGE, string.IsNullOrEmpty(channel) ? "MLAPI_DEFAULT_MESSAGE" : channel, clientIds, stream, security, null);
        }
예제 #3
0
        /// <summary>
        /// Sends unnamed message to a list of clients
        /// </summary>
        /// <param name="clientIds">The clients to send to, sends to everyone if null</param>
        /// <param name="buffer">The message stream containing the data</param>
        /// <param name="networkChannel">The channel to send the data on</param>
        public static void SendUnnamedMessage(List <ulong> clientIds, NetworkBuffer buffer, NetworkChannel networkChannel = NetworkChannel.Internal)
        {
            if (!NetworkManager.Singleton.IsServer)
            {
                if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                {
                    NetworkLog.LogWarning("Can not send unnamed messages to multiple users as a client");
                }
                return;
            }

            InternalMessageSender.Send(NetworkConstants.UNNAMED_MESSAGE, networkChannel, clientIds, buffer);
        }
예제 #4
0
        /// <summary>
        /// Sends a named message
        /// </summary>
        /// <param name="name">The message name to send</param>
        /// <param name="clientId">The client to send the message to</param>
        /// <param name="stream">The message stream containing the data</param>
        /// <param name="channel">The channel tos end the data on</param>
        /// <param name="security">The security settings to apply to the message</param>
        public static void SendNamedMessage(string name, ulong clientId, Stream stream, string channel = null, SecuritySendFlags security = SecuritySendFlags.None)
        {
            ulong hash = NetworkedBehaviour.HashMethodName(name);

            using (PooledBitStream messageStream = PooledBitStream.Get())
            {
                using (PooledBitWriter writer = PooledBitWriter.Get(messageStream))
                {
                    writer.WriteUInt64Packed(hash);
                }

                messageStream.CopyFrom(stream);

                InternalMessageSender.Send(clientId, MLAPIConstants.MLAPI_NAMED_MESSAGE, string.IsNullOrEmpty(channel) ? "MLAPI_DEFAULT_MESSAGE" : channel, messageStream, security, null);
            }
        }
예제 #5
0
        internal static void HandleServerRPCRequest(ulong clientId, Stream stream, string channelName, SecuritySendFlags security)
        {
            using (PooledBitReader reader = PooledBitReader.Get(stream))
            {
                ulong  networkId   = reader.ReadUInt64Packed();
                ushort behaviourId = reader.ReadUInt16Packed();
                ulong  hash        = reader.ReadUInt64Packed();
                ulong  responseId  = reader.ReadUInt64Packed();

                if (SpawnManager.SpawnedObjects.ContainsKey(networkId))
                {
                    NetworkedBehaviour behaviour = SpawnManager.SpawnedObjects[networkId].GetBehaviourAtOrderIndex(behaviourId);

                    if (behaviour == null)
                    {
                        if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                        {
                            LogHelper.LogWarning("ServerRPCRequest message recieved for a non existant behaviour. NetworkId: " + networkId + ", behaviourIndex: " + behaviourId);
                        }
                    }
                    else
                    {
                        object result = behaviour.OnRemoteServerRPC(hash, clientId, stream);

                        using (PooledBitStream responseStream = PooledBitStream.Get())
                        {
                            using (PooledBitWriter responseWriter = PooledBitWriter.Get(responseStream))
                            {
                                responseWriter.WriteUInt64Packed(responseId);
                                responseWriter.WriteObjectPacked(result);
                            }

                            InternalMessageSender.Send(clientId, MLAPIConstants.MLAPI_SERVER_RPC_RESPONSE, channelName, responseStream, security, SpawnManager.SpawnedObjects[networkId]);
                        }
                    }
                }
                else
                {
                    if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                    {
                        LogHelper.LogWarning("ServerRPCRequest message recieved for a non existant object with id: " + networkId + ". This message is lost.");
                    }
                }
            }
        }
예제 #6
0
        /// <summary>
        /// Generic Sending Method for Internal Messages
        /// TODO: Will need to open this up for discussion, but we will want to determine if this is how we want internal MLAPI command
        /// messages to be sent.  We might want specific commands to occur during specific network update regions (see NetworkUpdate
        /// </summary>
        public void InternalMessagesSendAndFlush()
        {
            foreach (RpcFrameQueueItem queueItem in m_InternalMLAPISendQueue)
            {
                var PoolStream = queueItem.NetworkBuffer;
                if (NetworkManager.Singleton.IsListening)
                {
                    switch (queueItem.QueueItemType)
                    {
                    case RpcQueueContainer.QueueItemType.CreateObject:
                    {
                        foreach (ulong clientId in queueItem.ClientNetworkIds)
                        {
                            InternalMessageSender.Send(clientId, NetworkConstants.ADD_OBJECT, queueItem.NetworkChannel, PoolStream);
                        }

                        PerformanceDataManager.Increment(ProfilerConstants.NumberOfRPCsSent, queueItem.ClientNetworkIds.Length);
                        ProfilerStatManager.RpcsSent.Record(queueItem.ClientNetworkIds.Length);
                        break;
                    }

                    case RpcQueueContainer.QueueItemType.DestroyObject:
                    {
                        foreach (ulong clientId in queueItem.ClientNetworkIds)
                        {
                            InternalMessageSender.Send(clientId, NetworkConstants.DESTROY_OBJECT, queueItem.NetworkChannel, PoolStream);
                        }

                        PerformanceDataManager.Increment(ProfilerConstants.NumberOfRPCsSent, queueItem.ClientNetworkIds.Length);
                        ProfilerStatManager.RpcsSent.Record(queueItem.ClientNetworkIds.Length);
                        break;
                    }
                    }
                }

                PoolStream.Dispose();
            }

            m_InternalMLAPISendQueue.Clear();
        }
        /// <summary>
        /// Sends the named message
        /// </summary>
        /// <param name="name">The message name to send</param>
        /// <param name="clientIds">The clients to send to, sends to everyone if null</param>
        /// <param name="stream">The message stream containing the data</param>
        /// <param name="networkChannel">The channel to send the data on</param>
        public static void SendNamedMessage(string name, List <ulong> clientIds, Stream stream, NetworkChannel networkChannel = NetworkChannel.Internal)
        {
            ulong hash = 0;

            switch (NetworkManager.Singleton.NetworkConfig.RpcHashSize)
            {
            case HashSize.VarIntTwoBytes:
                hash = name.GetStableHash16();
                break;

            case HashSize.VarIntFourBytes:
                hash = name.GetStableHash32();
                break;

            case HashSize.VarIntEightBytes:
                hash = name.GetStableHash64();
                break;
            }

            using (var messageBuffer = PooledNetworkBuffer.Get())
                using (var writer = PooledNetworkWriter.Get(messageBuffer))
                {
                    writer.WriteUInt64Packed(hash);

                    messageBuffer.CopyFrom(stream);

                    if (!NetworkManager.Singleton.IsServer)
                    {
                        if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                        {
                            NetworkLog.LogWarning("Can not send named messages to multiple users as a client");
                        }
                        return;
                    }

                    InternalMessageSender.Send(NetworkConstants.NAMED_MESSAGE, networkChannel, clientIds, messageBuffer);
                    PerformanceDataManager.Increment(ProfilerConstants.NamedMessageSent);
                }
        }
예제 #8
0
        /// <summary>
        /// Sends the named message
        /// </summary>
        /// <param name="name">The message name to send</param>
        /// <param name="clientIds">The clients to send to, sends to everyone if null</param>
        /// <param name="stream">The message stream containing the data</param>
        /// <param name="channel">The channel to send the data on</param>
        /// <param name="security">The security settings to apply to the message</param>
        public static void SendNamedMessage(string name, List <ulong> clientIds, Stream stream, string channel = null, SecuritySendFlags security = SecuritySendFlags.None)
        {
            ulong hash = NetworkedBehaviour.HashMethodName(name);

            using (PooledBitStream messageStream = PooledBitStream.Get())
            {
                using (PooledBitWriter writer = PooledBitWriter.Get(messageStream))
                {
                    writer.WriteUInt64Packed(hash);
                }

                messageStream.CopyFrom(stream);

                if (!NetworkingManager.Singleton.IsServer)
                {
                    if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
                    {
                        NetworkLog.LogWarning("Can not send named messages to multiple users as a client");
                    }
                    return;
                }
                if (clientIds == null)
                {
                    for (int i = 0; i < NetworkingManager.Singleton.ConnectedClientsList.Count; i++)
                    {
                        InternalMessageSender.Send(NetworkingManager.Singleton.ConnectedClientsList[i].ClientId, MLAPIConstants.MLAPI_NAMED_MESSAGE, string.IsNullOrEmpty(channel) ? "MLAPI_DEFAULT_MESSAGE" : channel, messageStream, security, null);
                    }
                }
                else
                {
                    for (int i = 0; i < clientIds.Count; i++)
                    {
                        InternalMessageSender.Send(clientIds[i], MLAPIConstants.MLAPI_NAMED_MESSAGE, string.IsNullOrEmpty(channel) ? "MLAPI_DEFAULT_MESSAGE" : channel, messageStream, security, null);
                    }
                }
            }
        }
예제 #9
0
        // Runs on client
        internal static void HandleHailRequest(ulong clientId, Stream stream)
        {
            X509Certificate2 certificate = null;

            byte[] serverDiffieHellmanPublicPart = null;
            using (PooledBitReader reader = PooledBitReader.Get(stream))
            {
                if (NetworkingManager.Singleton.NetworkConfig.EnableEncryption)
                {
                    // Read the certificate
                    if (NetworkingManager.Singleton.NetworkConfig.SignKeyExchange)
                    {
                        // Allocation justification: This runs on client and only once, at initial connection
                        certificate = new X509Certificate2(reader.ReadByteArray());
                        if (CryptographyHelper.VerifyCertificate(certificate, NetworkingManager.Singleton.ConnectedHostname))
                        {
                            // The certificate is not valid :(
                            // Man in the middle.
                            if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                            {
                                LogHelper.LogWarning("Invalid certificate. Disconnecting");
                            }
                            NetworkingManager.Singleton.StopClient();
                            return;
                        }
                        else
                        {
                            NetworkingManager.Singleton.NetworkConfig.ServerX509Certificate = certificate;
                        }
                    }

                    // Read the ECDH
                    // Allocation justification: This runs on client and only once, at initial connection
                    serverDiffieHellmanPublicPart = reader.ReadByteArray();

                    // Verify the key exchange
                    if (NetworkingManager.Singleton.NetworkConfig.SignKeyExchange)
                    {
                        int signatureType = reader.ReadByte();

                        byte[] serverDiffieHellmanPublicPartSignature = reader.ReadByteArray();

                        if (signatureType == 0)
                        {
                            RSACryptoServiceProvider rsa = certificate.PublicKey.Key as RSACryptoServiceProvider;

                            if (rsa != null)
                            {
                                using (SHA256Managed sha = new SHA256Managed())
                                {
                                    if (!rsa.VerifyData(serverDiffieHellmanPublicPart, sha, serverDiffieHellmanPublicPartSignature))
                                    {
                                        if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                                        {
                                            LogHelper.LogWarning("Invalid RSA signature. Disconnecting");
                                        }
                                        NetworkingManager.Singleton.StopClient();
                                        return;
                                    }
                                }
                            }
                            else
                            {
                                if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                                {
                                    LogHelper.LogWarning("No RSA key found in certificate. Disconnecting");
                                }
                                NetworkingManager.Singleton.StopClient();
                                return;
                            }
                        }
                        else if (signatureType == 1)
                        {
                            DSACryptoServiceProvider dsa = certificate.PublicKey.Key as DSACryptoServiceProvider;

                            if (dsa != null)
                            {
                                using (SHA256Managed sha = new SHA256Managed())
                                {
                                    if (!dsa.VerifyData(sha.ComputeHash(serverDiffieHellmanPublicPart), serverDiffieHellmanPublicPartSignature))
                                    {
                                        if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                                        {
                                            LogHelper.LogWarning("Invalid DSA signature. Disconnecting");
                                        }
                                        NetworkingManager.Singleton.StopClient();
                                        return;
                                    }
                                }
                            }
                            else
                            {
                                if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                                {
                                    LogHelper.LogWarning("No DSA key found in certificate. Disconnecting");
                                }
                                NetworkingManager.Singleton.StopClient();
                                return;
                            }
                        }
                        else
                        {
                            if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                            {
                                LogHelper.LogWarning("Invalid signature type. Disconnecting");
                            }
                            NetworkingManager.Singleton.StopClient();
                            return;
                        }
                    }
                }
            }

            using (PooledBitStream outStream = PooledBitStream.Get())
            {
                using (PooledBitWriter writer = PooledBitWriter.Get(outStream))
                {
                    if (NetworkingManager.Singleton.NetworkConfig.EnableEncryption)
                    {
                        // Create a ECDH key
                        EllipticDiffieHellman diffieHellman = new EllipticDiffieHellman(EllipticDiffieHellman.DEFAULT_CURVE, EllipticDiffieHellman.DEFAULT_GENERATOR, EllipticDiffieHellman.DEFAULT_ORDER);
                        NetworkingManager.Singleton.clientAesKey = diffieHellman.GetSharedSecret(serverDiffieHellmanPublicPart);
                        byte[] diffieHellmanPublicKey = diffieHellman.GetPublicKey();
                        writer.WriteByteArray(diffieHellmanPublicKey);
                    }
                }

                // Send HailResponse
                InternalMessageSender.Send(NetworkingManager.Singleton.ServerClientId, MLAPIConstants.MLAPI_CERTIFICATE_HAIL_RESPONSE, "MLAPI_INTERNAL", outStream, SecuritySendFlags.None, null);
            }
        }
예제 #10
0
        // Ran on server
        internal static void HandleHailResponse(ulong clientId, Stream stream)
        {
            if (!NetworkingManager.Singleton.PendingClients.ContainsKey(clientId) || NetworkingManager.Singleton.PendingClients[clientId].ConnectionState != PendingClient.State.PendingHail)
            {
                return;
            }
            if (!NetworkingManager.Singleton.NetworkConfig.EnableEncryption)
            {
                return;
            }

            using (PooledBitReader reader = PooledBitReader.Get(stream))
            {
                if (NetworkingManager.Singleton.PendingClients[clientId].KeyExchange != null)
                {
                    byte[] diffieHellmanPublic = reader.ReadByteArray();
                    NetworkingManager.Singleton.PendingClients[clientId].AesKey = NetworkingManager.Singleton.PendingClients[clientId].KeyExchange.GetSharedSecret(diffieHellmanPublic);
                    if (NetworkingManager.Singleton.NetworkConfig.SignKeyExchange)
                    {
                        byte[]                   diffieHellmanPublicSignature = reader.ReadByteArray();
                        X509Certificate2         certificate = NetworkingManager.Singleton.NetworkConfig.ServerX509Certificate;
                        RSACryptoServiceProvider rsa         = certificate.PrivateKey as RSACryptoServiceProvider;

                        if (rsa != null)
                        {
                            using (SHA256Managed sha = new SHA256Managed())
                            {
                                byte[] clientHash = rsa.Decrypt(diffieHellmanPublicSignature, false);
                                byte[] serverHash = sha.ComputeHash(diffieHellmanPublic);

                                if (!CryptographyHelper.ConstTimeArrayEqual(clientHash, serverHash))
                                {
                                    //Man in the middle.
                                    if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                                    {
                                        if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                                        {
                                            LogHelper.LogWarning("Signature doesnt match for the key exchange public part. Disconnecting");
                                        }
                                    }
                                    NetworkingManager.Singleton.DisconnectClient(clientId);
                                    return;
                                }
                            }
                        }
                        else
                        {
                            throw new CryptographicException("[MLAPI] Only RSA certificates are supported. No valid RSA key was found");
                        }
                    }
                }
            }

            NetworkingManager.Singleton.PendingClients[clientId].ConnectionState = PendingClient.State.PendingConnection;
            NetworkingManager.Singleton.PendingClients[clientId].KeyExchange     = null; // Give to GC

            // Send greetings, they have passed all the handshakes
            using (PooledBitStream outStream = PooledBitStream.Get())
            {
                using (PooledBitWriter writer = PooledBitWriter.Get(outStream))
                {
                    writer.WriteInt64Packed(DateTime.Now.Ticks); // This serves no purpose.
                }
                InternalMessageSender.Send(clientId, MLAPIConstants.MLAPI_GREETINGS, "MLAPI_INTERNAL", outStream, SecuritySendFlags.None, null, true);
            }
        }
예제 #11
0
 /// <summary>
 /// Sends a unnamed message to a specific client
 /// </summary>
 /// <param name="clientId">The client to send the message to</param>
 /// <param name="stream">The message stream containing the data</param>
 /// <param name="channel">The channel tos end the data on</param>
 /// <param name="security">The security settings to apply to the message</param>
 public static void SendUnnamedMessage(ulong clientId, BitStream stream, string channel = null, SecuritySendFlags security = SecuritySendFlags.None)
 {
     InternalMessageSender.Send(clientId, MLAPIConstants.MLAPI_UNNAMED_MESSAGE, string.IsNullOrEmpty(channel) ? "MLAPI_DEFAULT_MESSAGE" : channel, stream, security, null);
 }
 /// <summary>
 /// Sends a unnamed message to a specific client
 /// </summary>
 /// <param name="clientId">The client to send the message to</param>
 /// <param name="buffer">The message stream containing the data</param>
 /// <param name="networkChannel">The channel tos end the data on</param>
 public static void SendUnnamedMessage(ulong clientId, NetworkBuffer buffer, NetworkChannel networkChannel = NetworkChannel.Internal)
 {
     InternalMessageSender.Send(clientId, NetworkConstants.UNNAMED_MESSAGE, networkChannel, buffer);
     PerformanceDataManager.Increment(ProfilerConstants.UnnamedMessageSent);
 }
예제 #13
0
 /// <summary>
 /// Sends a unnamed message to a specific client
 /// </summary>
 /// <param name="clientId">The client to send the message to</param>
 /// <param name="buffer">The message stream containing the data</param>
 /// <param name="networkChannel">The channel tos end the data on</param>
 public static void SendUnnamedMessage(ulong clientId, NetworkBuffer buffer, NetworkChannel networkChannel = NetworkChannel.Internal)
 {
     InternalMessageSender.Send(clientId, NetworkConstants.UNNAMED_MESSAGE, networkChannel, buffer);
 }