示例#1
0
        /// <summary>
        /// Is called if the connection attempt resulted in a failure the remote connection point was unreachable or did not respond.
        /// </summary>
        /// <param name="response">Response information that may have been gathered upon the failure.</param>
        protected virtual void OnConnectionFailure(ConnectionResponse response)
        {
#if DEBUGBUILD
            //TODO: Add information to the debug logger string for the response.
            ClassLogger.LogDebug("Failed to connect to a server.");
#endif
            //Just fail silently if not overidden.
        }
示例#2
0
        /// <summary>
        /// Internally called by the app when a shutdown request has been recieved.
        /// </summary>
        internal void InternalOnShutdown()
        {
#if DEBUGBUILD
            ClassLogger.LogDebug("Server shutdown requested.");
#endif
            OnShutdown();

            //Do not stop polling the server until the application is about to stop.
            //In case it is desired to send a final message to clients and subservers we flush the network queue
            //So these messages can hopefully be sent before shutdown.
            this.lidgrenServerObj.FlushSendQueue();
            isReady = false;
        }
示例#3
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;
            }
        }
示例#4
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);
        }
示例#5
0
        //TODO: Address memory leak; not critical atm.
        private void ReadStatusChange(NetConnectionStatus netConnectionStatus, NetConnection netConnection)
        {
#if DEBUGBUILD
            this.ClassLogger.LogDebug("Entered into un-collected connection status handler.");
#endif

            //TODO: This whole method won't work if we don't achieve the connection and the list will continue to grow but it's not an imperative issue atm.
            ConnectionResponse cr = this.UnhandledServerConnections
                                    .FirstOrDefault(x => x.InternalNetConnection.RemoteUniqueIdentifier == netConnection.RemoteUniqueIdentifier);
            switch (netConnectionStatus)
            {
            case NetConnectionStatus.Disconnected:
                //If we get a disconnection and it's about an unhandled server that has yet to fully connect we should remove it.
                if (cr == null)
                {
                    return;
                }

                UnhandledServerConnections.Remove(cr);
                this.OnConnectionFailure(cr);
                break;

            case NetConnectionStatus.Connected:
                if (cr == null)
                {
                    return;
                }
#if DEBUGBUILD
                if (UnhandledServerConnections.Remove(cr))
                {
                    ClassLogger.LogDebug("Successfully removed a CR from a outgoing connection.");
                }
                else
                {
                    ClassLogger.LogDebug("Failed to remove a CR from a failed outgoing connection.");
                }
#else
                UnhandledServerConnections.Remove(cr);
#endif
                BuildServerPeer(netConnection, cr, ServerConnections);
                break;
            }
        }
示例#6
0
        private bool TryRegisterApprovedConnection(NetConnection netConnection, byte connectionType)
        {
            ClientPeer cp = OnAttemptedConnection(new ConnectionRequest(netConnection.RemoteEndPoint, netConnection.RemoteUniqueIdentifier,
                                                                        netConnection, connectionType));

            if (cp != null)
            {
                //A connecting subserver should be treated as a client connection. ServerPeers are peers that should be created
                //on the connected end, which can recieve events and responses, to its requests. So all approved connections should be added to the client
                //registry.
                ClassLogger.LogDebug("Connectiontype ID: " + connectionType);
#if DEBUGBUILD
                ClassLogger.LogDebug("Adding new client to ConnectionCollection. ID: " + cp.UniqueConnectionId);
#endif
                return(Clients.Register(new ConnectionPair <NetConnection, ClientPeer>(netConnection, cp), netConnection.RemoteUniqueIdentifier));
            }
            else
            {
                ClassLogger.LogDebug("ClientPeer generated for {0}:{1} ID: {2} is null.", netConnection.RemoteEndPoint.Address, netConnection.RemoteEndPoint.Port, netConnection.RemoteUniqueIdentifier);
            }

            return(false);
        }
示例#7
0
        protected virtual void OnRecieveMessage(NetIncomingMessage msg, bool isInternal)
        {
#if DEBUGBUILD
            ClassLogger.LogDebug("Recieved a high level message from client ID: " + msg.SenderConnection.RemoteUniqueIdentifier);
#endif

            if (Clients.HasKey(msg.SenderConnection.RemoteUniqueIdentifier))             //Client sent the message
            {
                NetworkMessageHandler.DispatchMessage(Clients[msg.SenderConnection.RemoteUniqueIdentifier].HighlevelPeer, msg, isInternal);
            }
            else if (ServerConnections.HasKey(msg.SenderConnection.RemoteUniqueIdentifier))             //Subserver sent a message
            {
                NetworkMessageHandler.DispatchMessage(ServerConnections[msg.SenderConnection.RemoteUniqueIdentifier].HighlevelPeer, msg, isInternal);
            }
            else
            {
                ClassLogger.LogWarn("Recieved highlevel message with no receving object.");
            }

            //At this point the message is for nobody and we shouldn't have recieved it.
            //In a perfect world we'd disconnect whoever sent it but we can't be sure a real client actually sent it
            //The package could be faked so just drop it.
        }
示例#8
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;
        }
示例#9
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);
            }
        }