Exemple #1
0
        private void ThreadWorker(Object parameters)
        {
            // Thread cache items
            ThreadParamInfo setupInfo;
            Address         serverAddress = new Address();
            Host            serverENetHost;
            Event           serverENetEvent;

            Peer[] serverPeerArray;

            // Grab the setup information.
            if (parameters.GetType() == typeof(ThreadParamInfo))
            {
                setupInfo = (ThreadParamInfo)parameters;
            }
            else
            {
                return;
            }

            // Attempt to initialize ENet inside the thread.
            if (Library.Initialize())
            {
            }
            else
            {
                return;
            }

            // Configure the server address.
            serverAddress.SetHost(setupInfo.Address);
            serverAddress.Port = (ushort)setupInfo.Port;
            serverPeerArray    = new Peer[setupInfo.Peers];

            using (serverENetHost = new Host())
            {
                // Create the server object.
                serverENetHost.Create(serverAddress, setupInfo.Peers, setupInfo.Channels);

                // Loop until we're told to cease operations.
                while (!CeaseOperation)
                {
                    // Intermission: Command Handling
                    while (Commands.TryDequeue(out IgnoranceCommandPacket commandPacket))
                    {
                        switch (commandPacket.Type)
                        {
                        default:
                            break;

                        // Boot a Peer off the Server.
                        case IgnoranceCommandType.ServerKickPeer:
                            uint targetPeer = commandPacket.PeerId;

                            if (!serverPeerArray[targetPeer].IsSet)
                            {
                                continue;
                            }

                            IgnoranceConnectionEvent iced = new IgnoranceConnectionEvent()
                            {
                                WasDisconnect = true,
                                NativePeerId  = targetPeer
                            };

                            DisconnectionEvents.Enqueue(iced);

                            // Disconnect and reset the peer array's entry for that peer.
                            serverPeerArray[targetPeer].DisconnectNow(0);
                            serverPeerArray[targetPeer] = default;
                            break;
                        }
                    }

                    // Step One:
                    // ---> Sending to peers
                    while (Outgoing.TryDequeue(out IgnoranceOutgoingPacket outgoingPacket))
                    {
                        // Only create a packet if the server knows the peer.
                        if (serverPeerArray[outgoingPacket.NativePeerId].IsSet)
                        {
                            int ret = serverPeerArray[outgoingPacket.NativePeerId].Send(outgoingPacket.Channel, ref outgoingPacket.Payload);
                        }
                        else
                        {
                            // A peer might have disconnected, this is OK - just log the packet if set to paranoid.
                        }
                    }

                    // Step 2
                    // <--- Receiving from peers
                    bool pollComplete = false;

                    while (!pollComplete)
                    {
                        Packet incomingPacket;
                        Peer   incomingPeer;
                        int    incomingPacketLength;

                        // Any events happening?
                        if (serverENetHost.CheckEvents(out serverENetEvent) <= 0)
                        {
                            // If service time is met, break out of it.
                            if (serverENetHost.Service(setupInfo.PollTime, out serverENetEvent) <= 0)
                            {
                                break;
                            }

                            pollComplete = true;
                        }

                        // Setup the packet references.
                        incomingPeer = serverENetEvent.Peer;

                        switch (serverENetEvent.Type)
                        {
                        // Idle.
                        case EventType.None:
                        default:
                            break;

                        // Connection Event.
                        case EventType.Connect:
                            IgnoranceConnectionEvent ice = new IgnoranceConnectionEvent()
                            {
                                NativePeerId = incomingPeer.ID,
                                IP           = incomingPeer.IP,
                                Port         = incomingPeer.Port
                            };

                            ConnectionEvents.Enqueue(ice);

                            // Assign a reference to the Peer.
                            serverPeerArray[incomingPeer.ID] = incomingPeer;
                            break;

                        // Disconnect/Timeout. Mirror doesn't care if it's either, so we lump them together.
                        case EventType.Disconnect:
                        case EventType.Timeout:
                            if (!serverPeerArray[incomingPeer.ID].IsSet)
                            {
                                break;
                            }

                            IgnoranceConnectionEvent iced = new IgnoranceConnectionEvent()
                            {
                                WasDisconnect = true,
                                NativePeerId  = incomingPeer.ID
                            };

                            DisconnectionEvents.Enqueue(iced);

                            // Reset the peer array's entry for that peer.
                            serverPeerArray[incomingPeer.ID] = default;
                            break;

                        case EventType.Receive:
                            // Receive event type usually includes a packet; so cache its reference.
                            incomingPacket = serverENetEvent.Packet;
                            if (!incomingPacket.IsSet)
                            {
                                break;
                            }

                            incomingPacketLength = incomingPacket.Length;

                            // Firstly check if the packet is too big. If it is, do not process it - drop it.
                            if (incomingPacketLength > setupInfo.PacketSizeLimit)
                            {
                                incomingPacket.Dispose();
                                break;
                            }

                            IgnoranceIncomingPacket incomingQueuePacket = new IgnoranceIncomingPacket
                            {
                                Channel      = serverENetEvent.ChannelID,
                                NativePeerId = incomingPeer.ID,
                                Payload      = incomingPacket,
                            };

                            // Enqueue.
                            Incoming.Enqueue(incomingQueuePacket);
                            break;
                        }
                    }
                }


                // Cleanup and flush everything.
                serverENetHost.Flush();

                // Kick everyone.
                for (int i = 0; i < serverPeerArray.Length; i++)
                {
                    if (!serverPeerArray[i].IsSet)
                    {
                        continue;
                    }
                    serverPeerArray[i].DisconnectNow(0);
                }
            }

            // Flush again to ensure ENet gets those Disconnection stuff out.
            // May not be needed; better to err on side of caution


            Library.Deinitialize();
        }
Exemple #2
0
        private void ThreadWorker(Object parameters)
        {
            if (Verbosity > 0)
            {
                Debug.Log("Ignorance Server: Initializing. Please stand by...");
            }

            // Thread cache items
            ThreadParamInfo setupInfo;
            Address         serverAddress = new Address();
            Host            serverENetHost;
            Event           serverENetEvent;

            Peer[] serverPeerArray;

            // Grab the setup information.
            if (parameters.GetType() == typeof(ThreadParamInfo))
            {
                setupInfo = (ThreadParamInfo)parameters;
            }
            else
            {
                Debug.LogError("Ignorance Server: Startup failure; Invalid thread parameters. Aborting.");
                return;
            }

            // Attempt to initialize ENet inside the thread.
            if (Library.Initialize())
            {
                Debug.Log("Ignorance Server: ENet Native successfully initialized.");
            }
            else
            {
                Debug.LogError("Ignorance Server: Failed to initialize ENet Native. This threads' f****d.");
                return;
            }

            // Configure the server address.
            serverAddress.SetHost(setupInfo.Address);
            serverAddress.Port = (ushort)setupInfo.Port;
            serverPeerArray    = new Peer[setupInfo.Peers];

            using (serverENetHost = new Host())
            {
                // Create the server object.
                serverENetHost.Create(serverAddress, setupInfo.Peers, setupInfo.Channels);

                // Loop until we're told to cease operations.
                while (!CeaseOperation)
                {
                    // Intermission: Command Handling
                    while (Commands.TryDequeue(out IgnoranceCommandPacket commandPacket))
                    {
                        switch (commandPacket.Type)
                        {
                        default:
                            break;

                        // Boot a Peer off the Server.
                        case IgnoranceCommandType.ServerKickPeer:
                            uint targetPeer = commandPacket.PeerId;

                            if (!serverPeerArray[targetPeer].IsSet)
                            {
                                continue;
                            }

                            if (setupInfo.Verbosity > 0)
                            {
                                Debug.Log($"Ignorance Server: Booting ENet Peer {targetPeer} off this server instance.");
                            }

                            IgnoranceConnectionEvent iced = new IgnoranceConnectionEvent
                            {
                                EventType    = 0x01,
                                NativePeerId = targetPeer
                            };

                            DisconnectionEvents.Enqueue(iced);

                            // Disconnect and reset the peer array's entry for that peer.
                            serverPeerArray[targetPeer].DisconnectNow(0);
                            serverPeerArray[targetPeer] = default;
                            break;
                        }
                    }

                    // Step One:
                    // ---> Sending to peers
                    while (Outgoing.TryDequeue(out IgnoranceOutgoingPacket outgoingPacket))
                    {
                        // Only create a packet if the server knows the peer.
                        if (serverPeerArray[outgoingPacket.NativePeerId].IsSet)
                        {
                            int ret = serverPeerArray[outgoingPacket.NativePeerId].Send(outgoingPacket.Channel, ref outgoingPacket.Payload);

                            if (ret < 0 && setupInfo.Verbosity > 0)
                            {
                                Debug.LogWarning($"Ignorance Server: ENet error {ret} while sending packet to Peer {outgoingPacket.NativePeerId}.");
                            }
                        }
                        else
                        {
                            // A peer might have disconnected, this is OK - just log the packet if set to paranoid.
                            if (setupInfo.Verbosity > 1)
                            {
                                Debug.LogWarning("Ignorance Server: Can't send packet, a native peer object is not set. This may be normal if the Peer has disconnected before this send cycle.");
                            }
                        }
                    }

                    // Step 2
                    // <--- Receiving from peers
                    bool pollComplete = false;

                    while (!pollComplete)
                    {
                        Packet incomingPacket;
                        Peer   incomingPeer;
                        int    incomingPacketLength;

                        // Any events happening?
                        if (serverENetHost.CheckEvents(out serverENetEvent) <= 0)
                        {
                            // If service time is met, break out of it.
                            if (serverENetHost.Service(setupInfo.PollTime, out serverENetEvent) <= 0)
                            {
                                break;
                            }

                            pollComplete = true;
                        }

                        // Setup the packet references.
                        incomingPeer = serverENetEvent.Peer;

                        // What type are you?
                        switch (serverENetEvent.Type)
                        {
                        // Idle.
                        case EventType.None:
                        default:
                            break;

                        // Connection Event.
                        case EventType.Connect:
                            if (setupInfo.Verbosity > 1)
                            {
                                Debug.Log($"Ignorance Server: Hello new peer with ID {incomingPeer.ID}!");
                            }

                            IgnoranceConnectionEvent ice = new IgnoranceConnectionEvent()
                            {
                                NativePeerId = incomingPeer.ID,
                                IP           = incomingPeer.IP,
                                Port         = incomingPeer.Port
                            };

                            ConnectionEvents.Enqueue(ice);

                            // Assign a reference to the Peer.
                            serverPeerArray[incomingPeer.ID] = incomingPeer;
                            break;

                        // Disconnect/Timeout. Mirror doesn't care if it's either, so we lump them together.
                        case EventType.Disconnect:
                        case EventType.Timeout:
                            if (!serverPeerArray[incomingPeer.ID].IsSet)
                            {
                                break;
                            }

                            if (setupInfo.Verbosity > 1)
                            {
                                Debug.Log($"Ignorance Server: Bye bye Peer {incomingPeer.ID}; They have disconnected.");
                            }

                            IgnoranceConnectionEvent iced = new IgnoranceConnectionEvent
                            {
                                EventType    = 0x01,
                                NativePeerId = incomingPeer.ID
                            };

                            DisconnectionEvents.Enqueue(iced);

                            // Reset the peer array's entry for that peer.
                            serverPeerArray[incomingPeer.ID] = default;
                            break;

                        case EventType.Receive:
                            // Receive event type usually includes a packet; so cache its reference.
                            incomingPacket = serverENetEvent.Packet;
                            if (!incomingPacket.IsSet)
                            {
                                if (setupInfo.Verbosity > 0)
                                {
                                    Debug.LogWarning($"Ignorance Server: A receive event did not supply us with a packet to work with. This should never happen.");
                                }
                                break;
                            }

                            incomingPacketLength = incomingPacket.Length;

                            // Firstly check if the packet is too big. If it is, do not process it - drop it.
                            if (incomingPacketLength > setupInfo.PacketSizeLimit)
                            {
                                if (setupInfo.Verbosity > 0)
                                {
                                    Debug.LogWarning($"Ignorance Server: Incoming packet is too big. My limit is {setupInfo.PacketSizeLimit} byte(s) whilest this packet is {incomingPacketLength} bytes.");
                                }

                                incomingPacket.Dispose();
                                break;
                            }

                            IgnoranceIncomingPacket incomingQueuePacket = new IgnoranceIncomingPacket
                            {
                                Channel      = serverENetEvent.ChannelID,
                                NativePeerId = incomingPeer.ID,
                                Payload      = incomingPacket,
                            };

                            // Enqueue.
                            Incoming.Enqueue(incomingQueuePacket);
                            break;
                        }
                    }
                }

                if (Verbosity > 0)
                {
                    Debug.Log("Ignorance Server: Thread shutdown commencing. Flushing connections.");
                }

                // Cleanup and flush everything.
                serverENetHost.Flush();

                // Kick everyone.
                for (int i = 0; i < serverPeerArray.Length; i++)
                {
                    if (!serverPeerArray[i].IsSet)
                    {
                        continue;
                    }
                    serverPeerArray[i].DisconnectNow(0);
                }
            }

            if (setupInfo.Verbosity > 0)
            {
                Debug.Log("Ignorance Server: Shutdown complete.");
            }

            Library.Deinitialize();
        }