Exemplo n.º 1
0
 public static void DecodeMessage(byte[] bytes, out String ID, out MISP.ScriptList Data)
 {
     Initialize();
     var datagram = new ReadOnlyDatagram(bytes);
     datagram.ReadString(out ID);
     Data = DecodeList(datagram);
 }
Exemplo n.º 2
0
        public ClientModule(System.Net.IPAddress host, int port, ClientGame parentGame)
        {
            netSession = new Network.ClientSession(0, new System.Net.IPEndPoint(host, port),
                    parentGame.Main.ScriptConsole.Write);

                netSession.onDatagramReceived += (data) =>
                {
                    var gram = new Network.ReadOnlyDatagram(data);
                    while (gram.More)
                    {
                        uint messageCode = 0;
                        gram.ReadUInt(out messageCode, 8);

                        switch (messageCode)
                        {
                            case 0:
                                if (simulation != null) throw new InvalidProgramException();
                                {
                                    String episodeName;
                                    uint version;
                                    gram.ReadString(out episodeName);
                                    gram.ReadUInt(out version, 32);
                                    parentGame.StartSimulation(episodeName, version);
                                }
                                break;
                            case 1:
                                {
                                    UInt32 entityID;
                                    UInt32 syncID;
                                    UInt32 dataLength;
                                    gram.ReadUInt(out entityID, 32);
                                    gram.ReadUInt(out syncID, 8);
                                    gram.ReadUInt(out dataLength, 32);
                                    var bytes = new byte[dataLength];
                                    gram.ReadBytes(bytes, dataLength);

                                    if (syncables.ContainsKey(entityID))
                                        foreach (var syncable in syncables[entityID])
                                            //if (syncable.SyncID == syncID)
                                                syncable.ReadFullSync(new ReadOnlyDatagram(bytes));
                                }
                                break;
                            case 2:
                                {
                                    UInt32 length;
                                    gram.ReadUInt(out length, 32);
                                    byte[] message = new byte[length];
                                    gram.ReadBytes(message, length);
                                    string messageID = null;
                                    MISP.ScriptList messageData = null;
                                    ScriptMessage.DecodeMessage(message, out messageID, out messageData);
                                    simulation.EnqueueEvent(messageID, messageData);
                                }
                                break;
                        }
                    }
                };

                parentGame.Main.Write("Connected to server " + host + " on port " + port + "\n");
        }
Exemplo n.º 3
0
        void IModule.BeginSimulation(Simulation sim)
        {
            this.sim = sim;
            sim.sendMessageHandler += (bytes) => { pendingMessages.Add(bytes); };

            try
            {
                netSession = new Network.ServerSession(port, sim.debug);

                netSession.onClientJoined += (client) =>
                {
                    var welcomeDatagram = new Network.WriteOnlyDatagram();
                    welcomeDatagram.WriteUInt(0, 8);
                    welcomeDatagram.WriteString(sim.Content.Module.Name);
                    welcomeDatagram.WriteUInt((uint)sim.Content.Module.Version, 32);
                    netSession.sendCriticalDatagram(client, welcomeDatagram.BufferAsArray, () =>
                    {
                        sim.EnqueueEvent("on-new-client", new MISP.ScriptList(client));
                    });
                };

                netSession.onDatagramReceived += (client, bytes) =>
                    {
                        var gram = new Network.ReadOnlyDatagram(bytes);
                        while (gram.More)
                        {
                            uint messageCode = 0;
                            gram.ReadUInt(out messageCode, 8);

                            switch (messageCode)
                            {
                                case 0:
                                    //Should never receive this message.
                                    break;
                                case 1:
                                    //Should never receive this message.
                                    break;
                                case 2:
                                    {
                                        UInt32 length;
                                        gram.ReadUInt(out length, 32);
                                        byte[] message = new byte[length];
                                        gram.ReadBytes(message, length);
                                        string messageID = null;
                                        MISP.ScriptList messageData = null;
                                        ScriptMessage.DecodeMessage(message, out messageID, out messageData);
                                        sim.EnqueueEvent(messageID, messageData);
                                    }
                                    break;
                            }
                        }
                    };
            }
            catch (Exception e)
            {
                System.Console.WriteLine("While trying to create a server module, " + e.Message);
                throw e;
            }
        }
Exemplo n.º 4
0
        public static void DecodeMessage(byte[] bytes, out String ID, out Common.ObjectList Data)
        {
            Initialize();
            var datagram = new ReadOnlyDatagram(bytes);

            datagram.ReadString(out ID);
            Data = DecodeList(datagram);
        }
Exemplo n.º 5
0
 private static MISP.ScriptList DecodeList(ReadOnlyDatagram datagram)
 {
     var r = new MISP.ScriptList();
     uint count = 0;
     datagram.ReadUInt(out count, 8);
     byte[] temp = new byte[4];
     for (int i = 0; i < count; ++i)
     {
         uint typeCode = 0;
         datagram.ReadUInt(out typeCode, 8);
         switch ((ScriptTypes)typeCode)
         {
             case ScriptTypes.List:
                 r.Add(DecodeList(datagram));
                 break;
             case ScriptTypes.String:
                 {
                     String s;
                     datagram.ReadString(out s);
                     r.Add(s);
                 }
                 break;
             case ScriptTypes.Int32:
                 datagram.ReadBytes(temp, 4);
                 r.Add(BitConverter.ToInt32(temp, 0));
                 break;
             case ScriptTypes.UInt32:
                 datagram.ReadBytes(temp, 4);
                 r.Add(BitConverter.ToUInt32(temp, 0));
                 break;
             case ScriptTypes.Single:
                 datagram.ReadBytes(temp, 4);
                 r.Add(BitConverter.ToSingle(temp, 0));
                 break;
             case ScriptTypes.Bool:
                 {
                     uint b = 0;
                     datagram.ReadUInt(out b, 8);
                     if (b == 0) r.Add(null);
                     else r.Add(true);
                 }
                 break;
             default:
                 throw new MISP.ScriptError("Error decoding message", null);
         }
     }
     return r;
 }
Exemplo n.º 6
0
        private static Common.ObjectList DecodeList(ReadOnlyDatagram datagram)
        {
            var  r     = new Common.ObjectList();
            uint count = 0;

            datagram.ReadUInt(out count, 8);
            byte[] temp = new byte[4];
            for (int i = 0; i < count; ++i)
            {
                uint typeCode = 0;
                datagram.ReadUInt(out typeCode, 8);
                switch ((ScriptTypes)typeCode)
                {
                case ScriptTypes.List:
                    r.Add(DecodeList(datagram));
                    break;

                case ScriptTypes.String:
                {
                    String s;
                    datagram.ReadString(out s);
                    r.Add(s);
                }
                break;

                case ScriptTypes.Int32:
                    datagram.ReadBytes(temp, 4);
                    r.Add(BitConverter.ToInt32(temp, 0));
                    break;

                case ScriptTypes.UInt32:
                    datagram.ReadBytes(temp, 4);
                    r.Add(BitConverter.ToUInt32(temp, 0));
                    break;

                case ScriptTypes.Single:
                    datagram.ReadBytes(temp, 4);
                    r.Add(BitConverter.ToSingle(temp, 0));
                    break;

                case ScriptTypes.Bool:
                {
                    uint b = 0;
                    datagram.ReadUInt(out b, 8);
                    if (b == 0)
                    {
                        r.Add(null);
                    }
                    else
                    {
                        r.Add(true);
                    }
                }
                break;

                default:
                    throw new InvalidProgramException("Error decoding message", null);
                }
            }
            return(r);
        }
Exemplo n.º 7
0
        public void update()
        {
            try
            {
                while (socket.Available > 0)
                {
                    IPEndPoint observedEndpoint = new IPEndPoint(IPAddress.Any, 0);
                    byte[]     bytes            = null;
                    try
                    {
                        bytes = socket.Receive(ref observedEndpoint);
                    }
                    catch (System.Net.Sockets.SocketException except)
                    {
                        _debug(0, "[SS] Receive threw an exception. Socket Error : " + except.SocketErrorCode);
                        continue;
                    }

                    _debug(1, "[SS] Incoming message of length " + bytes.Length.ToString() + " : " + BitConverter.ToString(bytes));
                    _debug(1, "[SS] It appears to have come from " + observedEndpoint.ToString());

                    var  datagram    = new ReadOnlyDatagram(bytes);
                    uint messageType = 0;
                    uint ackID       = 0;
                    if (!datagram.ReadUInt(out messageType, 8))
                    {
                        goto OnBadMessage;
                    }
                    if (!datagram.ReadUInt(out ackID, 32))
                    {
                        goto OnBadMessage;
                    }
                    var sendingClient = clients.FirstOrDefault((client) => { return(client.observedAddress.Equals(observedEndpoint)); });

                    switch ((ClientToServerMessage)messageType)
                    {
                    case ClientToServerMessage.Join:
                    {
                        if (sendingClient != null)         //Client has already joined - assume the ack was dropped.
                        {
                            _sendAckMessage(sendingClient, ackID);
                            break;
                        }

                        try
                        {
                            var newClient = new Client();
                            newClient.observedAddress   = observedEndpoint;
                            newClient.Guid              = Guid.NewGuid();
                            newClient.lastCommunication = DateTime.Now;


                            _debug(0, "[SS] A client with observed address " + observedEndpoint.ToString() + " has joined the session.");

                            foreach (var existingClient in clients)
                            {
                                _sendPeerJoinedMessage(existingClient, newClient);
                                _sendPeerJoinedMessage(newClient, existingClient);
                            }

                            clients.Add(newClient);
                            if (onClientJoined != null)
                            {
                                onClientJoined(newClient);
                            }

                            _sendAckMessage(newClient, ackID);
                        }
                        catch (Exception e)
                        {
                            _debug(0, "[SS] Accepting new client threw exception: " + e.Message);
                        }
                    }
                    break;

                    case ClientToServerMessage.Acknowledge:
                    {
                        var criticalDatagram = criticalDatagrams.FirstOrDefault((crit) => { return(crit.ackID == ackID); });
                        if (criticalDatagram != null)
                        {
                            if (!criticalDatagram.to.observedAddress.Equals(observedEndpoint))
                            {
                                _debug(1, "[SS] The observed endpoint of the ack reply does not match the known observed endpoint of the peer the datagram was sent to.");
                                break;
                            }
                            if (criticalDatagram.onSuccess != null)
                            {
                                try
                                {
                                    criticalDatagram.onSuccess();
                                }
                                catch (Exception) { }
                            }
                            criticalDatagrams.Remove(criticalDatagram);
                        }
                    }
                    break;

                    case ClientToServerMessage.Datagram:
                    {
                        if (sendingClient == null)
                        {
                            //_debug("[SS] I received a datagram from an unknown client with address " + observedEndpoint.ToString() +".");
                            break;
                        }

                        if (ackID != 0)
                        {
                            _sendAckMessage(sendingClient, ackID);
                            if (sendingClient.newDatagramReceived(ackID) == RemotePeer.DatagramResponse.Ignore)
                            {
                                break;
                            }
                        }

                        _debug(2, "[SS] I received a datagram from client " + sendingClient.Guid.ToString()
                               + ". It was " + (bytes.Length - 5).ToString() + " bytes long.");
                        if (bytes.Length - 5 <= 0)
                        {
                            goto OnBadMessage;
                        }
                        byte[] data = new byte[bytes.Length - 5];
                        if (!datagram.ReadBytes(data, (uint)(bytes.Length - 5)))
                        {
                            goto OnBadMessage;
                        }
                        if (onDatagramReceived != null)
                        {
                            onDatagramReceived(sendingClient, data);
                        }
                    }
                    break;
                    }
                    continue;
OnBadMessage:
                    {
                        _debug(1, "[SS] I received a bad message.");
                    }
                }

                var now = DateTime.Now;
                for (int i = 0; i < criticalDatagrams.Count;)
                {
                    var criticalDatagram = criticalDatagrams[i];
                    var timeDelta        = now - criticalDatagram.lastSendAttempt;
                    if (timeDelta.TotalMilliseconds > millisecondsBeforeRetry)
                    {
                        if (criticalDatagram.sendAttempts >= retryAttempts)
                        {
                            _debug(0, "[SS] I was not able to deliver critical packet " + criticalDatagram.ackID + ".");
                            criticalDatagrams.RemoveAt(i);
                            _onLostClient(criticalDatagram.to);
                            continue;
                        }

                        criticalDatagram.sendAttempts += 1;
                        _debug(2, "[SS] I am trying to send critical packet " + criticalDatagram.ackID + ". [" +
                               criticalDatagram.sendAttempts + " attempts]");
                        criticalDatagram.lastSendAttempt = now;
                        _send(criticalDatagram.data, criticalDatagram.to);
                    }

                    ++i;
                }

                foreach (var client in clients)
                {
                    var timeDelta = now - client.lastCommunication;
                    if (timeDelta.TotalMilliseconds > keepaliveRate)
                    {
                        _sendKeepalive(client);
                    }
                }
            }
            catch (Exception e) { _debug(0, e.Message + "\n" + e.StackTrace); }
        }
Exemplo n.º 8
0
        public void update()
        {
            try
            {
                while (socket.Available > 0)
                {
                    IPEndPoint observedEndpoint = new IPEndPoint(IPAddress.Any, 0);
                    byte[]     bytes            = null;
                    try
                    {
                        bytes = socket.Receive(ref observedEndpoint);
                    }
                    catch (System.Net.Sockets.SocketException except)
                    {
                        _debug("[CS] Receive threw an exception. Socket Error : " + except.SocketErrorCode);
                        onLostConnection();
                        continue;
                    }

                    //_debug("[CS] Incoming message of length " + bytes.Length.ToString() + " : " + BitConverter.ToString(bytes));
                    //_debug("[CS] It appears to have come from " + observedEndpoint.ToString());

                    if (!observedEndpoint.Equals(serverAddress))
                    {
                        _debug("[CS] I don't know who this message is from.");
                        continue;
                    }

                    var  datagram    = new ReadOnlyDatagram(bytes);
                    uint messageType = 0;
                    uint ackID       = 0;
                    if (!datagram.ReadUInt(out messageType, 8))
                    {
                        goto OnBadMessage;
                    }
                    if (!datagram.ReadUInt(out ackID, 32))
                    {
                        goto OnBadMessage;
                    }

                    if (ackID != 0)
                    {
                        _sendAckMessage(ackID);
                    }
                    if (messageType != (uint)ServerToClientMessage.Acknowledge &&
                        ackID != 0 &&
                        duplicateDatagramDetector.newDatagramReceived(ackID) == RemotePeer.DatagramResponse.Ignore)
                    {
                        continue;
                    }

                    switch ((ServerToClientMessage)messageType)
                    {
                    case ServerToClientMessage.Acknowledge:
                        _removeCriticalDatagram(ackID);
                        //if (ackID == 1) _debug("Received ACK for join");
                        break;

                    case ServerToClientMessage.Keepalive:
                    {
                        //Ack response already handled
                    }
                    break;

                    case ServerToClientMessage.PeerJoined:
                    {
                        var guidBytes = new byte[16];
                        if (!datagram.ReadBytes(guidBytes, 16))
                        {
                            goto OnBadMessage;
                        }
                        var peerGuid = new Guid(guidBytes);
                        var newPeer  = new Peer {
                            Guid = peerGuid
                        };
                        if (onPeerJoined != null)
                        {
                            onPeerJoined(newPeer);
                        }
                        peers.Add(newPeer);
                    }
                    break;

                    case ServerToClientMessage.PeerLeft:
                    {
                        var guidBytes = new byte[16];
                        if (!datagram.ReadBytes(guidBytes, 16))
                        {
                            goto OnBadMessage;
                        }
                        var peerGuid = new Guid(guidBytes);
                        var peer     = findPeer(peerGuid);
                        if (onPeerLeft != null)
                        {
                            onPeerLeft(peer);
                        }
                        peers.Remove(peer);
                    }
                    break;

                    case ServerToClientMessage.Datagram:
                    {
                        //_debug("[CS] I received a datagram from the server. It was " + (bytes.Length - 5).ToString() + " bytes long.");
                        if (bytes.Length - 5 <= 0)
                        {
                            goto OnBadMessage;
                        }
                        byte[] data = new byte[bytes.Length - 5];
                        if (!datagram.ReadBytes(data, (uint)(bytes.Length - 5)))
                        {
                            goto OnBadMessage;
                        }
                        if (onDatagramReceived != null)
                        {
                            try { onDatagramReceived(data); }
                            catch (Exception) { }
                        }
                        break;
                    }
                    }
                    continue;
OnBadMessage:
                    {
                        _debug("[CS] I received a bad message.");
                    }
                }

                var now = DateTime.Now;
                for (int i = 0; i < criticalDatagrams.Count;)
                {
                    var criticalDatagram = criticalDatagrams[i];
                    var timeDelta        = now - criticalDatagram.lastSendAttempt;
                    if (timeDelta.TotalMilliseconds > millisecondsBeforeRetry)
                    {
                        if (criticalDatagram.sendAttempts >= retryAttempts)
                        {
                            _debug("[CS] I was not able to deliver critical packet " + criticalDatagram.ackID + ".");
                            criticalDatagrams.RemoveAt(i);
                            _onLostConnection();
                            continue;
                        }

                        criticalDatagram.sendAttempts += 1;
                        //_debug("[CS] I am trying to send critical packet " + criticalDatagram.ackID + ". ["
                        //    + criticalDatagram.sendAttempts + " attempts]");
                        criticalDatagram.lastSendAttempt = now;
                        _send(criticalDatagram.data);
                    }

                    ++i;
                }
            }
            catch (Exception e)
            {
                _debug("[CS] " + e.Message + "\n" + e.StackTrace);
            }
        }
Exemplo n.º 9
0
        public void update()
        {
            try
            {
                while (socket.Available > 0)
                {
                    IPEndPoint observedEndpoint = new IPEndPoint(IPAddress.Any, 0);
                    byte[] bytes = null;
                    try
                    {
                        bytes = socket.Receive(ref observedEndpoint);
                    }
                    catch (System.Net.Sockets.SocketException except)
                    {
                        _debug("[SS] Receive threw an exception. Socket Error : " + except.SocketErrorCode);
                        continue;
                    }

                    _debug("[SS] Incoming message of length " + bytes.Length.ToString() + " : " + BitConverter.ToString(bytes));
                    _debug("[SS] It appears to have come from " + observedEndpoint.ToString());

                    var datagram = new ReadOnlyDatagram(bytes);
                    uint messageType = 0;
                    uint ackID = 0;
                    if (!datagram.ReadUInt(out messageType, 8)) goto OnBadMessage;
                    if (!datagram.ReadUInt(out ackID, 32)) goto OnBadMessage;
                    var sendingClient = clients.FirstOrDefault((client) => { return client.observedAddress.Equals(observedEndpoint); });

                    switch ((ClientToServerMessage)messageType)
                    {
                        case ClientToServerMessage.Join:
                            {
                                if (sendingClient != null)
                                {
                                    _sendAckMessage(sendingClient, ackID);
                                    break;
                                }

                                var newClient = new Client();
                                newClient.observedAddress = observedEndpoint;
                                newClient.Guid = Guid.NewGuid();
                                newClient.lastCommunication = DateTime.Now;

                                _sendAckMessage(newClient, ackID);

                                _debug("[SS] A client with observed address " + observedEndpoint.ToString() + " has joined the session.");

                                foreach (var existingClient in clients)
                                {
                                    _sendPeerJoinedMessage(existingClient, newClient);
                                    _sendPeerJoinedMessage(newClient, existingClient);
                                }

                                clients.Add(newClient);
                                if (onClientJoined != null) onClientJoined(newClient);
                            }
                            break;
                        case ClientToServerMessage.Acknowledge:
                            {
                                var criticalDatagram = criticalDatagrams.FirstOrDefault((crit) => { return crit.ackID == ackID; });
                                if (criticalDatagram != null)
                                {
                                    if (!criticalDatagram.to.observedAddress.Equals(observedEndpoint))
                                    {
                                        _debug("[SS] The observed endpoint of the ack reply does not match the known observed endpoint of the peer the datagram was sent to.");
                                        break;
                                    }
                                    if (criticalDatagram.onSuccess != null)
                                    {
                                        try
                                        {
                                            criticalDatagram.onSuccess();
                                        }
                                        catch (Exception) { }
                                    }
                                    criticalDatagrams.Remove(criticalDatagram);
                                }
                            }
                            break;
                       case ClientToServerMessage.Datagram:
                            {
                                if (sendingClient == null)
                                {
                                    _debug("[SS] I received a datagram from an unknown client with address " + observedEndpoint.ToString() +".");
                                    break;
                                }

                                if (ackID != 0)
                                {
                                    _sendAckMessage(sendingClient, ackID);
                                    if (sendingClient.newDatagramReceived(ackID) == RemotePeer.DatagramResponse.Ignore)
                                        break;
                                }

                                _debug("[SS] I received a datagram from client " + sendingClient.Guid.ToString()
                                    + ". It was " + (bytes.Length - 5).ToString() + " bytes long.");
                                if (bytes.Length - 5 <= 0) goto OnBadMessage;
                                byte[] data = new byte[bytes.Length - 5];
                                if (!datagram.ReadBytes(data, (uint)(bytes.Length - 5))) goto OnBadMessage;
                                if (onDatagramReceived != null) onDatagramReceived(sendingClient, data);
                            }
                            break;
                    }
                    continue;
                OnBadMessage:
                    {
                        _debug("[SS] I received a bad message.");
                    }
                }

                var now = DateTime.Now;
                for (int i = 0; i < criticalDatagrams.Count; )
                {
                    var criticalDatagram = criticalDatagrams[i];
                    var timeDelta = now - criticalDatagram.lastSendAttempt;
                    if (timeDelta.TotalMilliseconds > millisecondsBeforeRetry)
                    {
                        if (criticalDatagram.sendAttempts >= retryAttempts)
                        {
                            _debug("[SS] I was not able to deliver critical packet " + criticalDatagram.ackID + ".");
                            criticalDatagrams.RemoveAt(i);
                            _onLostClient(criticalDatagram.to);
                            continue;
                        }

                        criticalDatagram.sendAttempts += 1;
                        _debug("[SS] I am trying to send critical packet " + criticalDatagram.ackID + ". [" +
                            criticalDatagram.sendAttempts + " attempts]");
                        criticalDatagram.lastSendAttempt = now;
                        _send(criticalDatagram.data, criticalDatagram.to);
                    }

                    ++i;
                }

                foreach (var client in clients)
                {
                    var timeDelta = now - client.lastCommunication;
                    if (timeDelta.TotalMilliseconds > keepaliveRate)
                        _sendKeepalive(client);
                }
            }
            catch (Exception e) { _debug(e.Message + "\n" + e.StackTrace); }
        }
Exemplo n.º 10
0
        public void update()
        {
            try
            {
                while (socket.Available > 0)
                {
                    IPEndPoint observedEndpoint = new IPEndPoint(IPAddress.Any, 0);
                    byte[] bytes = null;
                    try
                    {
                        bytes = socket.Receive(ref observedEndpoint);
                    }
                    catch (System.Net.Sockets.SocketException except)
                    {
                        _debug("[CS] Receive threw an exception. Socket Error : " + except.SocketErrorCode);
                        onLostConnection();
                        continue;
                    }

                    _debug("[CS] Incoming message of length " + bytes.Length.ToString() + " : " + BitConverter.ToString(bytes));
                    _debug("[CS] It appears to have come from " + observedEndpoint.ToString());

                    if (!observedEndpoint.Equals(serverAddress))
                    {
                        _debug("[CS] I don't know who this message is from.");
                        continue;
                    }

                    var datagram = new ReadOnlyDatagram(bytes);
                    uint messageType = 0;
                    uint ackID = 0;
                    if (!datagram.ReadUInt(out messageType, 8)) goto OnBadMessage;
                    if (!datagram.ReadUInt(out ackID, 32)) goto OnBadMessage;

                    if (ackID != 0) _sendAckMessage(ackID);
                    if (messageType != (uint)ServerToClientMessage.Acknowledge &&
                        ackID != 0 &&
                        duplicateDatagramDetector.newDatagramReceived(ackID) == RemotePeer.DatagramResponse.Ignore)
                        continue;

                    switch ((ServerToClientMessage)messageType)
                    {
                        case ServerToClientMessage.Acknowledge:
                            _removeCriticalDatagram(ackID);
                            break;
                        case ServerToClientMessage.Keepalive:
                            {
                                //Ack response already handled
                            }
                            break;
                        case ServerToClientMessage.PeerJoined:
                            {
                                var guidBytes = new byte[16];
                                if (!datagram.ReadBytes(guidBytes, 16)) goto OnBadMessage;
                                var peerGuid = new Guid(guidBytes);
                                var newPeer = new Peer { Guid = peerGuid };
                                if (onPeerJoined != null) onPeerJoined(newPeer);
                                peers.Add(newPeer);
                            }
                            break;
                        case ServerToClientMessage.PeerLeft:
                            {
                                var guidBytes = new byte[16];
                                if (!datagram.ReadBytes(guidBytes, 16)) goto OnBadMessage;
                                var peerGuid = new Guid(guidBytes);
                                var peer = findPeer(peerGuid);
                                if (onPeerLeft != null) onPeerLeft(peer);
                                peers.Remove(peer);
                            }
                            break;
                        case ServerToClientMessage.Datagram:
                            {
                                _debug("[CS] I received a datagram from the server. It was " + (bytes.Length - 5).ToString() + " bytes long.");
                                if (bytes.Length - 5 <= 0) goto OnBadMessage;
                                byte[] data = new byte[bytes.Length - 5];
                                if (!datagram.ReadBytes(data, (uint)(bytes.Length - 5))) goto OnBadMessage;
                                if (onDatagramReceived != null)
                                {
                                    try { onDatagramReceived(data); }
                                    catch (Exception) { }
                                }
                                break;
                            }
                    }
                    continue;
                OnBadMessage:
                    {
                        _debug("[CS] I received a bad message.");
                    }
                }

                var now = DateTime.Now;
                for (int i = 0; i < criticalDatagrams.Count; )
                {
                    var criticalDatagram = criticalDatagrams[i];
                    var timeDelta = now - criticalDatagram.lastSendAttempt;
                    if (timeDelta.TotalMilliseconds > millisecondsBeforeRetry)
                    {
                        if (criticalDatagram.sendAttempts >= retryAttempts)
                        {
                            _debug("[CS] I was not able to deliver critical packet " + criticalDatagram.ackID + ".");
                            criticalDatagrams.RemoveAt(i);
                            _onLostConnection();
                            continue;
                        }

                        criticalDatagram.sendAttempts += 1;
                        _debug("[CS] I am trying to send critical packet " + criticalDatagram.ackID + ". ["
                            + criticalDatagram.sendAttempts + " attempts]");
                        criticalDatagram.lastSendAttempt = now;
                        _send(criticalDatagram.data);
                    }

                    ++i;
                }
            }
            catch (Exception e) { _debug("[CS] " + e.Message + "\n" + e.StackTrace); }
        }