Beispiel #1
0
        private bool EncryptionRegisterFromWire(Peer toPassTo, PacketBase packet)
        {
            EncryptionRequest eq = packet as EncryptionRequest;

            if (eq == null)
            {
                ClassLogger.LogError("Recieved encryption request with null packet.");
                return(false);
            }

            if (!EncryptionFactory.ContainsKey(eq.EncryptionByteType))
            {
                ClassLogger.LogError("Failed to establish encryption from Peer ID: "
                                     + toPassTo.UniqueConnectionId + " with EncryptionByte: " + eq.EncryptionByteType);
                return(false);
            }

            EncryptionBase newEncryptionObj = EncryptionFactory[eq.EncryptionByteType]();

            toPassTo.EncryptionRegister.Register(newEncryptionObj, eq.EncryptionByteType);

            bool result = toPassTo.EncryptionRegister[eq.EncryptionByteType]
                          .SetNetworkInitRequiredData(eq.EncryptionInitInfo);

            if (result)
            {
                EncryptionRequest encryptionResponse =
                    new EncryptionRequest(eq.EncryptionByteType, newEncryptionObj.NetworkInitRequiredData());

                toPassTo.SendMessage(Packet.OperationType.Response, encryptionResponse, (byte)InternalPacketCode.EncryptionRequest,
                                     Packet.DeliveryMethod.ReliableUnordered, 0, 0, true);
            }

            return(false);
        }
Beispiel #2
0
        private bool ProcessEncryptionResponse(Peer peer, PacketBase packet)
        {
            EncryptionRequest eq = packet as EncryptionRequest;

            if (eq == null)
            {
                ClassLogger.LogError("Recieved encryption request with null packet.");
                return(false);
            }

            if (!peer.EncryptionRegister.HasKey(eq.EncryptionByteType))
            {
                ClassLogger.LogError("Recieved an encryption request response from the server for ByteType: {0} but the client is unaware of that type."
                                     , eq.EncryptionByteType);
                return(false);
            }

            //TODO: Verify that this is working. Callback at one point was not working.
            //This will set the server's init info. In the case of the default, for example, it will set the Diffiehelmman public key.
            //With this the server and client have established a shared secret and can now pass messages, with the IV, to eachother securely.
            //In the case of a custom method it is User defined and should be referenced.
            bool result = peer.EncryptionRegister[eq.EncryptionByteType].SetNetworkInitRequiredData(eq.EncryptionInitInfo);

            Action callback = peer.EncryptionRegister[eq.EncryptionByteType].OnEstablished;

            if (callback != null)
            {
                callback();
            }

            return(result);
        }
Beispiel #3
0
        private bool HandleInternalMessage(Peer toPassTo, LidgrenTransferPacket packet)
        {
            if (packet.isEncrypted)
            {
                if (toPassTo.EncryptionRegister.HasKey(packet.EncryptionMethodByte))
                {
                    if (!packet.Decrypt(toPassTo.EncryptionRegister[packet.EncryptionMethodByte]))
                    {
                        ClassLogger.LogError("Failed to decrypt package from Peer ID: "
                                             + toPassTo.UniqueConnectionId + " with EncryptionByte: " + packet.EncryptionMethodByte);
                        return(false);
                    }
                }
            }

            PacketBase deserializedPacketBase = InternalPacketConstructor(packet);

            switch (packet.OperationType)
            {
            case Packet.OperationType.Request:
                return(this.ProcessInternalRequest((InternalPacketCode)packet.PacketCode, deserializedPacketBase, toPassTo));

            case Packet.OperationType.Response:
                return(this.ProcessInternalResponse((InternalPacketCode)packet.PacketCode, deserializedPacketBase, toPassTo));

            case Packet.OperationType.Event:
                throw new LoggableException("GladNet currently does not support internal events.", null, LogType.Error);

            default:
                return(false);
            }
        }
Beispiel #4
0
        public virtual bool DispatchMessage(Peer toPassTo, NetIncomingMessage msg, bool isInternal)
        {
            if (msg == null)
            {
                throw new LoggableException("When dispatched NetBuffer was found to be null.", null, LogType.Error);
            }

            LidgrenTransferPacket packet = this.BuildTransferPacket(msg);

            if (toPassTo == null)
            {
                return(false);
            }

            if (!this.SerializerRegister.HasKey(packet.SerializerKey))
            {
                ClassLogger.LogError("Recieved a packet that cannot be handled due to not having a serializer registered with byte code: " + packet.SerializerKey);
                return(false);
            }

            if (packet == null)
            {
                ClassLogger.LogError("Lidgren packet built to null.");
                return(false);
            }

            if (toPassTo == null)
            {
                ClassLogger.LogError("When attempted to dispatch the Peer passed was found to be null.");
                return(false);
            }

#if UNITYDEBUG || DEBUG
            this.ClassLogger.LogDebug("About to handle packet. Encrypted: " + packet.isEncrypted.ToString() + " EncryptionCode: " + packet.EncryptionMethodByte);
#endif

            if (!isInternal)
            {
                if (packet.isEncrypted)
                {
                    return(DispatchEncryptedMessage(toPassTo, packet, msg.DeliveryMethod));
                }
                else
                {
                    return(Dispatch(toPassTo, packet, msg.DeliveryMethod));
                }
            }
            else
            {
                return(HandleInternalMessage(toPassTo, packet));
            }
        }
Beispiel #5
0
        private void ServiceLidgrenMessage(NetIncomingMessage msg)
        {
            if (msg == null)
            {
                return;
            }

            switch (msg.MessageType)
            {
            case NetIncomingMessageType.StatusChanged:
                try
                {
                    HandleStatusChange((NetConnectionStatus)msg.ReadByte());
                }
                catch (NetException e)
                {
#if UNITYDEBUG
                    ClassLogger.LogError("Malformed packet recieved. Packet indicated that it was a status change but had no info.");
#else
                    //TODO: What shall we do when the packet is malformed here?
#endif
                }
                catch (LoggableException e)
                {
                    //Checking this because it can cause some nasty GC to make these string adds.
                    if (ClassLogger.isStateEnabled(LogType.Debug))
                    {
                        ClassLogger.LogDebug(e.Message + " Inner: " + e.InnerException != null ? e.InnerException.Message : "");
                    }
                }
                break;

            //We can take advantage of using the same logic for both cases.
            //All that changes is we till the handler it is an internal message for a Data message type.
            case NetIncomingMessageType.ExternalHighlevelMessage:
            case NetIncomingMessageType.Data:
                try
                {
                    this.NetworkMessageHandler.DispatchMessage(this, msg, msg.MessageType == NetIncomingMessageType.Data);
                }
                catch (LoggableException e)
                {
                    //Checking this because it can cause some nasty GC to make these string adds.
                    if (ClassLogger.isStateEnabled(LogType.Debug))
                    {
                        ClassLogger.LogDebug(e.Message + " Inner: " + e.InnerException != null ? e.InnerException.Message : "");
                    }
                }
                break;
            }
        }
Beispiel #6
0
        public void StartListener()
        {
            if (networkThread != null)
            {
                ClassLogger.LogError("Attempted to start listener while listener is spinning.");
#if !UNITYDEBUG && !UNITYRELEASE
                //TODO: Better exception throwing
                throw new Exception("Attempted to start listener while listener is spinning.");
#endif
            }

            //If we hit this point we need to make a network thread to poll the lidgren client and process incoming client data.
            networkThread = new Thread(new ThreadStart(NetworkListenerThreadMethod));
            networkThread.Start();
        }
Beispiel #7
0
        private bool DispatchEncryptedMessage(Peer toPassTo, LidgrenTransferPacket packet, NetDeliveryMethod method)
        {
            if (!toPassTo.EncryptionRegister.HasKey(packet.EncryptionMethodByte))
            {
                ClassLogger.LogError("Failed to decrypt packet. Client requested unregistered method: " + packet.EncryptionMethodByte);
                return(false);
            }

            try
            {
                switch (packet.OperationType)
                {
                case Packet.OperationType.Event:
                    EventPackage ep = this.GeneratePackage <EventPackage>(packet, toPassTo.EncryptionRegister[packet.EncryptionMethodByte]);
                    if (ep != null)
                    {
                        toPassTo.PackageRecieve(ep, new MessageInfo(packet, method));
                    }
                    return(true);

                case Packet.OperationType.Request:
                    RequestPackage rqp = this.GeneratePackage <RequestPackage>(packet, toPassTo.EncryptionRegister[packet.EncryptionMethodByte]);
                    if (rqp != null)
                    {
                        toPassTo.PackageRecieve(rqp, new MessageInfo(packet, method));
                    }
                    return(true);

                case Packet.OperationType.Response:
                    ResponsePackage rp = this.GeneratePackage <ResponsePackage>(packet, toPassTo.EncryptionRegister[packet.EncryptionMethodByte]);
                    if (rp != null)
                    {
                        toPassTo.PackageRecieve(rp, new MessageInfo(packet, method));
                    }
                    return(true);

                default:
                    return(false);
                }
            }
            catch (LoggableException e)
            {
                ClassLogger.LogError(e.Message + e.InnerException != null ? " Inner: " + e.InnerException : "");
                return(false);
            }
        }
Beispiel #8
0
        //TODO: Totally refactor this garbage
        public void StartPipeListener(string clientHandleString)
        {
#if DEBUGBUILD
            ClassLogger.LogDebug("Started pipe listener to launcher with handle: " + clientHandleString);
#endif

            Task.Factory.StartNew(() =>
            {
                try
                {
                    using (PipeStream ps = new AnonymousPipeClientStream(PipeDirection.In, clientHandleString))
                    {
                        using (StreamReader reader = new StreamReader(ps, Encoding.Default))
                        {
                            string message;
                            while (true)
                            {
                                message = reader.ReadLine();

                                if (message != null)
                                {
#if DEBUGBUILD
                                    ClassLogger.LogDebug("Recieved message via Launcher pipe: " + message);
#endif


                                    if (message.Contains("[SHUTDOWN]"))
                                    {
                                        if (message == "[SHUTDOWN] " + Process.GetCurrentProcess().Id.ToString())
                                        {
                                            isReady = false;
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    ClassLogger.LogError(e.Message);
                }
            }, TaskCreationOptions.LongRunning);
        }
Beispiel #9
0
        private bool Dispatch(Peer toPassTo, IPackage packet, NetDeliveryMethod method)
        {
            try
            {
                //TODO: Refactor
                switch ((Packet.OperationType)packet.OperationType)
                {
                case Packet.OperationType.Event:
                    EventPackage ePackage = GeneratePackage <EventPackage>(packet);
                    if (ePackage != null)
                    {
                        toPassTo.PackageRecieve(ePackage, new MessageInfo(method));
                    }
                    return(true);

                case Packet.OperationType.Request:
                    //ClassLogger.LogDebug("Hit request");
                    RequestPackage rqPackage = GeneratePackage <RequestPackage>(packet);
                    if (rqPackage != null)
                    {
                        //ClassLogger.LogDebug("About to call peer method");
                        toPassTo.PackageRecieve(rqPackage, new MessageInfo(method));
                    }
                    return(true);

                case Packet.OperationType.Response:
                    ResponsePackage rPackage = GeneratePackage <ResponsePackage>(packet);
                    if (rPackage != null)
                    {
                        toPassTo.PackageRecieve(rPackage, new MessageInfo(method));
                    }
                    return(true);

                default:
                    return(false);
                }
            }
            catch (LoggableException e)
            {
                ClassLogger.LogError(e.Message + e.InnerException != null ? " Inner: " + e.InnerException : "");
                return(false);
            }
        }
Beispiel #10
0
        public bool Connect(string ip, int port, string hailMessage, string appName)
        {
            if (isConnected)
            {
                this.Disconnect();
            }

            NetPeerConfiguration config = new NetPeerConfiguration(appName);

            config.AcceptIncomingConnections = false;

            if (ip == null || appName == null || ip.Length == 0)
            {
                ClassLogger.LogError("Connection to remote host must have a valid appname and IP address.");
#if UNITYDEBUG || UNITYRELEASE
                return(false);
#else
                throw new NullReferenceException("Connection to remote host must have a valid appname and IP address.");
#endif
            }

            //This should reduce GC which is always terrible for Unity.
            config.UseMessageRecycling = true;

            internalLidgrenClient = new NetClient(config);
            internalLidgrenClient.Start();

            NetOutgoingMessage msg = GenerateClientHail(hailMessage);

            IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(ip), port);

            NetConnection connection = internalLidgrenClient.Connect(endPoint, msg);

            this.SetConnectionDetails(connection, endPoint, connection.RemoteUniqueIdentifier);

            _isConnected = true;

            Interlocked.Exchange(ref timeNowByPoll, NetTime.Now < 3 ? 0 : NetTime.Now);
            Interlocked.Exchange(ref timeNowByPollComparer, NetTime.Now < 3 ? 0 : NetTime.Now);

            return(true);
        }
Beispiel #11
0
        private PacketBase InternalPacketConstructor(IPackage package)
        {
            SerializerBase serializer = this.SerializerRegister[package.SerializerKey];

            if (serializer == null)
            {
                ClassLogger.LogError("Failed to deserialize internal message with serializer key: " + package.SerializerKey);
                return(null);
            }

            PacketBase packet = this.Converter.PacketConstructor(package.InternalByteRepresentation, serializer);

            if (packet == null)
            {
                ClassLogger.LogError("Recieved a null internal package. Code: {0} SerializerKey: {1}",
                                     package.PacketCode, package.SerializerKey);
            }

            return(packet);
        }
Beispiel #12
0
        private NetOutgoingMessage GenerateClientHail(string hail)
        {
            if (internalLidgrenClient != null)
            {
                NetOutgoingMessage msg = internalLidgrenClient.CreateMessage();

                //This indicates we're a pure client connection. It is a reserved connection type value.
                msg.Write(hail);
                msg.Write((byte)0);

                return(msg);
            }
            else
            {
#if UNITYDEBUG || UNITYRELEASE
                ClassLogger.LogError("Internal lidgren client is null. Do not invoke HailMessageGeneration via reflection.");
                return(null);
#else
                throw new NullReferenceException("internalLidgrenClient is null for some reason.");
#endif
            }
        }
Beispiel #13
0
        //This is not needed by the client
        /// <summary>
        /// Registers an encryption object. This will request that the encryption be established by sending a message to the server.
        /// Do not try to register an encryption object if you are not connected.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="encryptorInstance"></param>
        /// <returns></returns>
        public bool Register <T>(T encryptorInstance, Action OnSuccess) where T : EncryptionBase
        {
            if (encryptorInstance == null)
            {
                ClassLogger.LogError("Cannot register a null encryption object.");
                return(false);
            }

            if (this.EncryptionRegister.HasKey(encryptorInstance.EncryptionTypeByte))
            {
                ClassLogger.LogError("Tried to register an already known encryption object.");
                return(false);
            }

            encryptorInstance.OnEstablished += OnSuccess;

            this.EncryptionRegister.Register(encryptorInstance, encryptorInstance.EncryptionTypeByte);

            PacketBase packet = new EncryptionRequest(encryptorInstance.EncryptionTypeByte, encryptorInstance.NetworkInitRequiredData());

            return(this.SendMessage(Packet.OperationType.Request, packet, (byte)InternalPacketCode.EncryptionRequest,
                                    Packet.DeliveryMethod.ReliableUnordered, 0, 0, true) != Packet.SendResult.FailedNotConnected);
        }
Beispiel #14
0
        private void RegisterProtobufPackets(Func <Type, bool> registerAsDefaultFunc)
        {
            if (RecieverListener == null)
            {
                ClassLogger.LogError("The IListener instance passed in on connection is a null reference.");
                return;
            }

            try
            {
                //Registering the empty packet
                Packet.Register(typeof(EmptyPacket), true);
                Packet.Register(typeof(EncryptionRequest), true);

                Packet.SetupProtoRuntimePacketInheritance();
                this.RecieverListener.RegisterProtobufPackets(registerAsDefaultFunc);
                Packet.LockInProtobufnet();
            }
            catch (LoggableException e)
            {
                ClassLogger.LogError(e.Message + e.InnerException != null ? e.InnerException.Message : "");
                throw;
            }
        }
Beispiel #15
0
        //This is not needed by the client
        /// <summary>
        /// Registers an encryption object. This will request that the encryption be established by sending a message to the server.
        /// Do not try to register an encryption object if you are not connected.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="encryptorInstance"></param>
        /// <returns></returns>
        public bool Register <T>(T encryptorInstance) where T : EncryptionBase
        {
            if (encryptorInstance == null)
            {
                ClassLogger.LogError("Cannot register a null encryption object.");
                return(false);
            }

            if (this.EncryptionRegister.HasKey(encryptorInstance.EncryptionTypeByte))
            {
                ClassLogger.LogError("Tried to register an already known encryption object.");
                return(false);
            }

            if (!isConnected || RecieverListener == null)
            {
                ClassLogger.LogError("Cannot register encryption objects when not connected.");
                return(false);
            }

            //Set the callback for when the server acknowledges our encryption request.
            encryptorInstance.OnEstablished += () =>
            {
                lock (networkIncomingEnqueueSyncObj)
                {
                    this.networkPackageQueue.Enqueue(() => { RecieverListener.OnStatusChange(StatusChange.EncryptionEstablished); });
                }
            };

            this.EncryptionRegister.Register(encryptorInstance, encryptorInstance.EncryptionTypeByte);

            PacketBase packet = new EncryptionRequest(encryptorInstance.EncryptionTypeByte, encryptorInstance.NetworkInitRequiredData());

            return(this.SendMessage(Packet.OperationType.Request, packet, (byte)InternalPacketCode.EncryptionRequest,
                                    Packet.DeliveryMethod.ReliableUnordered, 0, 0, true) != Packet.SendResult.FailedNotConnected);
        }
Beispiel #16
0
        private void NetworkListenerThreadMethod()
        {
#if UNITYDEBUG || DEBUG
            ClassLogger.LogDebug("Started network thread.");
#endif


            if (internalLidgrenClient == null || internalLidgrenClient == null)
            {
                ClassLogger.LogError("Cannot start listening before connecting.");

#if !UNITYDEBUG && !UNITYRELEASE
                ClassLogger.LogError("Cannot start listening before connecting.");
                throw new NullReferenceException("Cannot start listening before connecting. Internally a client object is null.");
#endif
            }

            NetIncomingMessage msg;

            try
            {
                while (_isConnected)
                {
                    msg = internalLidgrenClient.WaitMessage(20);

                    //TODO: May not be thread safe due to NetTime.Now
                    //This checks to see if Poll was called in the last 3 seconds. If it was not it stops the network thread basically.
                    if (Interlocked.Exchange(ref timeNowByPollComparer, timeNowByPoll) < NetTime.Now - 3)
                    {
#if UNITYDEBUG || DEBUG
                        ClassLogger.LogDebug("Stopping network thread.");
#endif
                        _isConnected = false;
                        //Should be thread safe and fine to do.
                        this.Disconnect();
                    }

                    if (msg != null)
                    {
                        try
                        {
                            ServiceLidgrenMessage(msg);

                            //Recycling the message reduces GC which can be make or break for Unity.
                            this.internalLidgrenClient.Recycle(msg);
                        }
                        //We can catch nullreferences here without affecting exceptions external to the library
                        //This is because we have a Queue<Action> and thus we can't possibly catch the exception coming from the main thread via the lambda generated Action instance.
                        catch (NullReferenceException e)
                        {
                            ClassLogger.LogError("Error occurred during polling: " + e.Message + " StackTrace: " + e.StackTrace + " Source: " + e.Source);
                            //If we hit this point it generally means that the object has gone out of scope for some reason without disconnecting (usually in Unity going from playmode
                            //to the editor so at this point we should just catch it and let the application and thread die.
                            _isConnected = false;
                        }
                    }
                }
            }
            catch (LoggableException e)
            {
                ClassLogger.LogError(e.Message + e.InnerException != null ? "Inner: " + e.InnerException : "");
            }
            catch (Exception e)
            {
                ClassLogger.LogError(e.Message + e.Data);
                throw;
            }

            Disconnect();

            networkThread = null;
        }
Beispiel #17
0
        private void MessagePoll(NetPeer peer)
        {
            //TODO: Examine if this will cause latency issues for handling messages
            //This is done so that CPU usage isn't too high. It blocks the thread and waits for a message
            //Nothing but GladNet should be executing on the main thread anyway.
            NetIncomingMessage msg = peer.WaitMessage(10);

            //TODO: Refactor
            if (msg != null && msg.SenderConnection != null)
            {
#if DEBUGBUILD
                ClassLogger.LogDebug("Recieved a message from client ID: " + msg.SenderConnection.RemoteUniqueIdentifier);
#endif
                switch (msg.MessageType)
                {
                case NetIncomingMessageType.ConnectionApproval:
                    ClassLogger.LogDebug("Hit connection approval");
                    if (this.NetworkMessageHandler.TryReadHailMessage(msg, ExpectedClientHailMessage))
                    {
                        ClassLogger.LogDebug("About to approve.");
                        try
                        {
                            msg.SenderConnection.Approve();
                            this.TryRegisterApprovedConnection(msg.SenderConnection, msg.SenderConnection.RemoteHailMessage.ReadByte());
                        }
                        catch (NetException e)
                        {
#if DEBUGBUILD
                            ClassLogger.LogError("Failed to read connection type byte from hail message packet. Exception: " + e.Message);
#endif
                        }
                    }
                    else
                    {
                        ClassLogger.LogWarn("Client failed to satisfy hailmessage. Expected: " + ExpectedClientHailMessage);
                    }

                    break;

                case NetIncomingMessageType.StatusChanged:
                    //Malicious user could try to send a fake StatusChange without the extra byte so try to catch NetException.
                    try
                    {
                        if (Clients.HasKey(msg.SenderConnection.RemoteUniqueIdentifier))
                        {
                            this.ReadStatusChange((NetConnectionStatus)msg.ReadByte(), Clients[msg.SenderConnection.RemoteUniqueIdentifier]);
                        }
                        else if (ServerConnections.HasKey(msg.SenderConnection.RemoteUniqueIdentifier))
                        {
                            this.ReadStatusChange((NetConnectionStatus)msg.ReadByte(), ServerConnections[msg.SenderConnection.RemoteUniqueIdentifier]);
                        }
                        else
                        {
                            //If this point is reached it indicates that the status change is not from a registered connection and
                            //this could indicate potentially a subserver connecting or maybe a client message before hail approval.
                            ReadStatusChange((NetConnectionStatus)msg.ReadByte(), msg.SenderConnection);
                        }
                    }
                    catch (NetException e)
                    {
#if DEBUGBUILD
                        ClassLogger.LogError("NetConnection ID: " + msg.SenderConnection.RemoteUniqueIdentifier + " sent a potentially malicious StatusChange update. Error: " + e.Message);
#endif
                    }
                    break;

                case NetIncomingMessageType.ExternalHighlevelMessage:
                    OnRecieveMessage(msg, false);
                    break;

                case NetIncomingMessageType.Data:
                    OnRecieveMessage(msg, true);
                    break;
                }

                peer.Recycle(msg);
            }
        }