Exemple #1
0
        private void HandleSplitMessage(PlayerNetworkSession playerSession, ConnectedPackage package, SplitPartPackage splitMessage)
        {
            int spId    = package._splitPacketId;
            int spIdx   = package._splitPacketIndex;
            int spCount = package._splitPacketCount;

            if (!playerSession.Splits.ContainsKey(spId))
            {
                playerSession.Splits.TryAdd(spId, new SplitPartPackage[spCount]);
            }

            SplitPartPackage[] spPackets = playerSession.Splits[spId];
            spPackets[spIdx] = splitMessage;

            bool haveEmpty = false;

            for (int i = 0; i < spPackets.Length; i++)
            {
                haveEmpty = haveEmpty || spPackets[i] == null;
            }

            if (!haveEmpty)
            {
                Log.DebugFormat("Got all {0} split packages for split ID: {1}", spCount, spId);

                SplitPartPackage[] waste;
                playerSession.Splits.TryRemove(spId, out waste);

                MemoryStream stream = new MemoryStream();
                for (int i = 0; i < spPackets.Length; i++)
                {
                    SplitPartPackage splitPartPackage = spPackets[i];
                    byte[]           buf = splitPartPackage.Message;
                    stream.Write(buf, 0, buf.Length);
                    splitPartPackage.PutPool();
                }

                byte[] buffer = stream.ToArray();

                byte id = buffer[0];
                if (id == 0x8e)
                {
                    id = buffer[1];
                }

                Package fullMessage = PackageFactory.CreatePackage(id, buffer) ?? new UnknownPackage(id, buffer);
                fullMessage.DatagramSequenceNumber = package._datagramSequenceNumber;
                fullMessage.OrderingChannel        = package._orderingChannel;
                fullMessage.OrderingIndex          = package._orderingIndex;

                if (!(fullMessage is McpeBatch))
                {
                    Log.Debug($"Split: {fullMessage.GetType().Name} 0x{fullMessage.Id:x2} \n{Package.HexDump(buffer)}");
                }

                HandlePackage(fullMessage);
                fullMessage.PutPool();
            }
        }
Exemple #2
0
        private void SendDatagram(PlayerNetworkSession session, Datagram datagram)
        {
            if (datagram.MessageParts.Count != 0)
            {
                datagram.Header.datagramSequenceNumber = Interlocked.Increment(ref Session.DatagramSequenceNumber);
                byte[] data = datagram.Encode();

                datagram.Timer.Restart();
                SendData(data, _serverEndpoint);
            }
        }
Exemple #3
0
        public bool StartServer()
        {
            if (Listener != null)
            {
                return(false);                              // Already started
            }
            try
            {
                Log.Info("Initializing...");

                Listener = new UdpClient(_clientEndpoint);

                if (IsRunningOnMono())
                {
                    Listener.Client.ReceiveBufferSize = 1024 * 1024 * 3;
                    Listener.Client.SendBufferSize    = 4096;
                }
                else
                {
                    Listener.Client.ReceiveBufferSize = int.MaxValue;
                    Listener.Client.SendBufferSize    = int.MaxValue;
                    Listener.DontFragment             = false;

                    // SIO_UDP_CONNRESET (opcode setting: I, T==3)
                    // Windows:  Controls whether UDP PORT_UNREACHABLE messages are reported.
                    // - Set to TRUE to enable reporting.
                    // - Set to FALSE to disable reporting.

                    uint IOC_IN            = 0x80000000;
                    uint IOC_VENDOR        = 0x18000000;
                    uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
                    Listener.Client.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);

                    ////
                    ////WARNING: We need to catch errors here to remove the code above.
                    ////
                }

                Session = new PlayerNetworkSession(null, _clientEndpoint);

                Listener.BeginReceive(ReceiveCallback, Listener);

                Log.InfoFormat("Server open for business for {0}", Username);

                return(true);
            }
            catch (Exception e)
            {
                Log.Error(e);
                StopServer();
            }

            return(false);
        }
Exemple #4
0
        public void StartClient()
        {
            if (UdpClient != null)
            {
                return;
            }

            try
            {
                Log.Info("Initializing...");

                UdpClient = new UdpClient(_clientEndpoint)
                {
                    Client =
                    {
                        ReceiveBufferSize = int.MaxValue,
                        SendBufferSize    = int.MaxValue
                    },
                    DontFragment = false
                };

                // SIO_UDP_CONNRESET (opcode setting: I, T==3)
                // Windows:  Controls whether UDP PORT_UNREACHABLE messages are reported.
                // - Set to TRUE to enable reporting.
                // - Set to FALSE to disable reporting.

                //uint IOC_IN = 0x80000000;
                //uint IOC_VENDOR = 0x18000000;
                //uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
                //UdpClient.Client.IOControl((int) SIO_UDP_CONNRESET, new byte[] {Convert.ToByte(false)}, null);

                ////
                ////WARNING: We need to catch errors here to remove the code above.
                ////

                Session = new PlayerNetworkSession(null, _clientEndpoint);

                UdpClient.BeginReceive(ReceiveCallback, UdpClient);
                _clientEndpoint = (IPEndPoint)UdpClient.Client.LocalEndPoint;

                Log.InfoFormat("Server open for business for {0}", Username);

                return;
            }
            catch (Exception e)
            {
                Log.Error("Main loop", e);
                StopClient();
            }
        }
Exemple #5
0
        private void HandleSplitMessage(PlayerNetworkSession playerSession, ConnectedPackage package, SplitPartPackage splitMessage)
        {
            int spId    = package._splitPacketId;
            int spIdx   = package._splitPacketIndex;
            int spCount = package._splitPacketCount;

            if (!playerSession.Splits.ContainsKey(spId))
            {
                playerSession.Splits.Add(spId, new SplitPartPackage[spCount]);
            }

            SplitPartPackage[] spPackets = playerSession.Splits[spId];
            spPackets[spIdx] = splitMessage;

            bool haveEmpty = false;

            for (int i = 0; i < spPackets.Length; i++)
            {
                haveEmpty = haveEmpty || spPackets[i] == null;
            }

            if (!haveEmpty)
            {
                Log.DebugFormat("Got all {0} split packages for split ID: {1}", spCount, spId);

                MemoryStream stream = new MemoryStream();
                for (int i = 0; i < spPackets.Length; i++)
                {
                    SplitPartPackage splitPartPackage = spPackets[i];
                    byte[]           buf = splitPartPackage.Message;
                    stream.Write(buf, 0, buf.Length);
                    splitPartPackage.PutPool();
                }

                playerSession.Splits.Remove(spId);

                byte[] buffer = stream.ToArray();

                Package fullMessage = PackageFactory.CreatePackage(buffer[0], buffer) ?? new UnknownPackage(buffer[0], buffer);
                fullMessage.DatagramSequenceNumber = package._datagramSequenceNumber;
                fullMessage.OrderingChannel        = package._orderingChannel;
                fullMessage.OrderingIndex          = package._orderingIndex;
                HandlePackage(fullMessage);
                fullMessage.PutPool();
            }
        }
Exemple #6
0
        public static IEnumerable <Datagram> CreateDatagrams(Package message, int mtuSize, PlayerNetworkSession session)
        {
            if (message is InternalPing)
            {
                yield break;
            }

            Datagram datagram = CreateObject();
            //datagram.Reset();

            var messageParts = GetMessageParts(message, mtuSize, Reliability.Reliable, ref session.ReliableMessageNumber);

            foreach (var messagePart in messageParts)
            {
                if (!datagram.TryAddMessagePart(messagePart, mtuSize))
                {
                    yield return(datagram);

                    datagram = CreateObject();
                    //datagram.Reset();

                    if (!datagram.TryAddMessagePart(messagePart, mtuSize))
                    {
                        Log.Warn(string.Format("Message part too big for a single datagram. Size: {0}, MTU: {1}", messagePart.Encode().Length, mtuSize));
                        throw new Exception(string.Format("Message part too big for a single datagram. Size: {0}, MTU: {1}", messagePart.Encode().Length, mtuSize));
                    }
                }
            }

            yield return(datagram);
        }
Exemple #7
0
        private static List <MessagePart> GetMessageParts(Packet message, int mtuSize, Reliability reliability, PlayerNetworkSession session)
        {
            var messageParts = new List <MessagePart>();

            Memory <byte> encodedMessage = message.Encode();
            //if (Log.IsDebugEnabled && message is McpeBatch)
            //	Log.Debug($"0x{encodedMessage[0]:x2}\n{Package.HexDump(encodedMessage)}");

            int orderingIndex = 0;

            if (!(message is ConnectedPong) && !(message is DetectLostConnections))
            {
                reliability = Reliability.ReliableOrdered;
            }

            CryptoContext cryptoContext = session.CryptoContext;

            if (cryptoContext != null && !(message is ConnectedPong) && !(message is DetectLostConnections))
            {
                lock (session.EncodeSync)
                {
                    reliability = Reliability.ReliableOrdered;

                    var isBatch = message is McpeWrapper;

                    if (!message.ForceClear && session.CryptoContext.UseEncryption)
                    {
                        if (isBatch)
                        {
                            encodedMessage = encodedMessage.Slice(1);
                        }
                        else
                        {
                            encodedMessage = Compression.Compress(encodedMessage, true, encodedMessage.Length > 1000 ? CompressionLevel.Fastest : CompressionLevel.NoCompression);
                        }

                        McpeWrapper wrapper = McpeWrapper.CreateObject();
                        wrapper.payload = CryptoUtils.Encrypt(encodedMessage, cryptoContext);
                        encodedMessage  = wrapper.Encode();
                        wrapper.PutPool();
                    }
                    else if (!isBatch)
                    {
                        McpeWrapper wrapper = McpeWrapper.CreateObject();
                        wrapper.payload = Compression.Compress(encodedMessage, true, encodedMessage.Length > 1000 ? CompressionLevel.Fastest : CompressionLevel.NoCompression);
                        encodedMessage  = wrapper.Encode();
                        wrapper.PutPool();
                    }
                    //if (Log.IsDebugEnabled)
                    //	Log.Debug($"0x{encodedMessage[0]:x2}\n{Package.HexDump(encodedMessage)}");
                }
            }
            //if (Log.IsDebugEnabled)
            //	Log.Debug($"0x{encodedMessage[0]:x2}\n{Package.HexDump(encodedMessage)}");

            if (reliability == Reliability.ReliableOrdered)
            {
                orderingIndex = Interlocked.Increment(ref session.OrderingIndex);
            }

            if (encodedMessage.IsEmpty)
            {
                return(messageParts);
            }

            int datagramHeaderSize = 100;
            int count = (int)Math.Ceiling(encodedMessage.Length / ((double)mtuSize - datagramHeaderSize));
            int index = 0;

            if (session.SplitPartId > short.MaxValue - 100)
            {
                Interlocked.CompareExchange(ref session.SplitPartId, 0, short.MaxValue);
            }

            short splitId = (short)Interlocked.Increment(ref session.SplitPartId);

            if (count <= 1)
            {
                MessagePart messagePart = MessagePart.CreateObject();
                messagePart.Header.Reliability           = reliability;
                messagePart.Header.ReliableMessageNumber = Interlocked.Increment(ref session.ReliableMessageNumber);
                messagePart.Header.HasSplit        = count > 1;
                messagePart.Header.PartCount       = count;
                messagePart.Header.PartId          = splitId;
                messagePart.Header.PartIndex       = index++;
                messagePart.Header.OrderingChannel = 0;
                messagePart.Header.OrderingIndex   = orderingIndex;
                messagePart.ContainedMessageId     = message.Id;
                messagePart.Buffer = encodedMessage.ToArray();

                messageParts.Add(messagePart);
            }
            else
            {
                foreach ((int from, int to)span in ArraySplit(encodedMessage.Length, mtuSize - datagramHeaderSize))
                {
                    MessagePart messagePart = MessagePart.CreateObject();
                    messagePart.Header.Reliability           = reliability;
                    messagePart.Header.ReliableMessageNumber = Interlocked.Increment(ref session.ReliableMessageNumber);
                    messagePart.Header.HasSplit        = count > 1;
                    messagePart.Header.PartCount       = count;
                    messagePart.Header.PartId          = splitId;
                    messagePart.Header.PartIndex       = index++;
                    messagePart.Header.OrderingChannel = 0;
                    messagePart.Header.OrderingIndex   = orderingIndex;
                    messagePart.ContainedMessageId     = message.Id;
                    messagePart.Buffer = encodedMessage.Slice(span.from, span.to);

                    messageParts.Add(messagePart);
                }
            }

            return(messageParts);
        }
Exemple #8
0
        public static IEnumerable <Datagram> CreateDatagrams(Packet message, int mtuSize, PlayerNetworkSession session)
        {
            if (message is InternalPing)
            {
                yield break;
            }

            Datagram datagram = CreateObject();

            List <MessagePart> messageParts = GetMessageParts(message, mtuSize, Reliability.Reliable, session);

            foreach (var messagePart in messageParts)
            {
                if (!datagram.TryAddMessagePart(messagePart, mtuSize))
                {
                    yield return(datagram);

                    datagram = CreateObject();
                    if (datagram.MessageParts.Count != 0)
                    {
                        throw new Exception("Excepted no message parts in new message");
                    }

                    if (!datagram.TryAddMessagePart(messagePart, mtuSize))
                    {
                        string error = $"Message part too big for a single datagram. Size: {messagePart.Encode().Length}, MTU: {mtuSize}";
                        Log.Error(error);
                        throw new Exception(error);
                    }
                }
            }

            yield return(datagram);
        }
Exemple #9
0
        public static void CreateDatagrams(List <Package> messages, int mtuSize, ref int reliableMessageNumber, PlayerNetworkSession session, Action <PlayerNetworkSession, Datagram> sendDatagram)
        {
            Datagram datagram = null;

            foreach (var message in messages)
            {
                if (message is InternalPing)
                {
                    continue;
                }

                var messageParts = GetMessageParts(message, mtuSize, Reliability.Reliable, ref reliableMessageNumber);
                foreach (var messagePart in messageParts)
                {
                    if (datagram == null)
                    {
                        datagram = CreateObject();
                    }

                    if (!datagram.TryAddMessagePart(messagePart, mtuSize))
                    {
                        Datagram datagram1 = datagram;
                        sendDatagram(session, datagram1);

                        datagram = CreateObject();

                        if (!datagram.TryAddMessagePart(messagePart, mtuSize))
                        {
                            throw new Exception(string.Format("Message part too big for a single datagram. Size: {0}, MTU: {1}", messagePart.Encode().Length, mtuSize));
                        }
                    }
                }
            }

            if (datagram != null)
            {
                sendDatagram(session, datagram);
            }
        }
Exemple #10
0
        private void HandleSplitMessage(PlayerNetworkSession playerSession, ConnectedPackage package, SplitPartPackage splitMessage)
        {
            int spId = package._splitPacketId;
            int spIdx = package._splitPacketIndex;
            int spCount = package._splitPacketCount;

            if (!playerSession.Splits.ContainsKey(spId))
            {
                playerSession.Splits.TryAdd(spId, new SplitPartPackage[spCount]);
            }

            SplitPartPackage[] spPackets = playerSession.Splits[spId];
            spPackets[spIdx] = splitMessage;

            bool haveEmpty = false;
            for (int i = 0; i < spPackets.Length; i++)
            {
                haveEmpty = haveEmpty || spPackets[i] == null;
            }

            if (!haveEmpty)
            {
                Log.DebugFormat("Got all {0} split packages for split ID: {1}", spCount, spId);

                SplitPartPackage[] waste;
                playerSession.Splits.TryRemove(spId, out waste);

                MemoryStream stream = new MemoryStream();
                for (int i = 0; i < spPackets.Length; i++)
                {
                    SplitPartPackage splitPartPackage = spPackets[i];
                    byte[] buf = splitPartPackage.Message;
                    stream.Write(buf, 0, buf.Length);
                    splitPartPackage.PutPool();
                }

                byte[] buffer = stream.ToArray();

                Package fullMessage = PackageFactory.CreatePackage(buffer[0], buffer) ?? new UnknownPackage(buffer[0], buffer);
                fullMessage.DatagramSequenceNumber = package._datagramSequenceNumber;
                fullMessage.OrderingChannel = package._orderingChannel;
                fullMessage.OrderingIndex = package._orderingIndex;
                HandlePackage(fullMessage);
                fullMessage.PutPool();
            }
        }
Exemple #11
0
        public void StartClient()
        {
            if (UdpClient != null) return;

            try
            {
                Log.Info("Initializing...");

                UdpClient = new UdpClient(_clientEndpoint)
                {
                    Client =
                    {
                        ReceiveBufferSize = int.MaxValue,
                        SendBufferSize = int.MaxValue
                    },
                    DontFragment = false
                };

                // SIO_UDP_CONNRESET (opcode setting: I, T==3)
                // Windows:  Controls whether UDP PORT_UNREACHABLE messages are reported.
                // - Set to TRUE to enable reporting.
                // - Set to FALSE to disable reporting.

                //uint IOC_IN = 0x80000000;
                //uint IOC_VENDOR = 0x18000000;
                //uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
                //UdpClient.Client.IOControl((int) SIO_UDP_CONNRESET, new byte[] {Convert.ToByte(false)}, null);

                ////
                ////WARNING: We need to catch errors here to remove the code above.
                ////

                Session = new PlayerNetworkSession(null, _clientEndpoint);

                UdpClient.BeginReceive(ReceiveCallback, UdpClient);
                _clientEndpoint = (IPEndPoint) UdpClient.Client.LocalEndPoint;

                Log.InfoFormat("Server open for business for {0}", Username);

                return;
            }
            catch (Exception e)
            {
                Log.Error("Main loop", e);
                StopClient();
            }
        }
Exemple #12
0
        private void SendDatagram(PlayerNetworkSession session, Datagram datagram)
        {
            if (datagram.MessageParts.Count != 0)
            {
                datagram.Header.datagramSequenceNumber = Interlocked.Increment(ref Session.DatagramSequenceNumber);
                byte[] data = datagram.Encode();

                datagram.Timer.Restart();
                SendData(data, _serverEndpoint);
            }
        }
Exemple #13
0
        private static List <MessagePart> GetMessageParts(Package message, int mtuSize, Reliability reliability, PlayerNetworkSession session)
        {
            var messageParts = new List <MessagePart>();

            byte[] encodedMessage = message.Encode();

            int orderingIndex = 0;

            CryptoContext cryptoContext = session.CryptoContext;

            if (cryptoContext != null && !(message is ConnectedPong) && !(message is DetectLostConnections))
            {
                lock (session.EncodeSync)
                {
                    McpeWrapper wrapper = McpeWrapper.CreateObject();
                    reliability   = Reliability.ReliableOrdered;
                    orderingIndex = Interlocked.Increment(ref session.OrderingIndex);

                    if (!message.ForceClear && session.CryptoContext.UseEncryption)
                    {
                        wrapper.payload = CryptoUtils.Encrypt(encodedMessage, cryptoContext);
                    }
                    else
                    {
                        wrapper.payload = encodedMessage;
                    }

                    encodedMessage = wrapper.Encode();
                    //if (Log.IsDebugEnabled)
                    //	Log.Debug($"0x{encodedMessage[0]:x2}\n{Package.HexDump(encodedMessage)}");
                    wrapper.PutPool();
                }
            }
            //if (Log.IsDebugEnabled)
            //	Log.Debug($"0x{encodedMessage[0]:x2}\n{Package.HexDump(encodedMessage)}");

            if (encodedMessage == null)
            {
                return(messageParts);
            }

            int datagramHeaderSize = 100;
            int count = (int)Math.Ceiling(encodedMessage.Length / ((double)mtuSize - datagramHeaderSize));
            int index = 0;

            if (session.SplitPartId > short.MaxValue - 100)
            {
                Interlocked.CompareExchange(ref session.SplitPartId, 0, short.MaxValue);
            }

            short splitId = (short)Interlocked.Increment(ref session.SplitPartId);

            if (count <= 1)
            {
                MessagePart messagePart = MessagePart.CreateObject();
                messagePart.Header.Reliability           = reliability;
                messagePart.Header.ReliableMessageNumber = Interlocked.Increment(ref session.ReliableMessageNumber);
                messagePart.Header.HasSplit        = count > 1;
                messagePart.Header.PartCount       = count;
                messagePart.Header.PartId          = splitId;
                messagePart.Header.PartIndex       = index++;
                messagePart.Header.OrderingChannel = 0;
                messagePart.Header.OrderingIndex   = orderingIndex;
                messagePart.ContainedMessageId     = message.Id;
                messagePart.Buffer = encodedMessage;

                messageParts.Add(messagePart);
            }
            else
            {
                foreach (var bytes in ArraySplit(encodedMessage, mtuSize - datagramHeaderSize))
                {
                    MessagePart messagePart = MessagePart.CreateObject();
                    messagePart.Header.Reliability           = reliability;
                    messagePart.Header.ReliableMessageNumber = Interlocked.Increment(ref session.ReliableMessageNumber);
                    messagePart.Header.HasSplit        = count > 1;
                    messagePart.Header.PartCount       = count;
                    messagePart.Header.PartId          = splitId;
                    messagePart.Header.PartIndex       = index++;
                    messagePart.Header.OrderingChannel = 0;
                    messagePart.Header.OrderingIndex   = orderingIndex;
                    messagePart.ContainedMessageId     = message.Id;
                    messagePart.Buffer = bytes;

                    messageParts.Add(messagePart);
                }
            }

            return(messageParts);
        }
Exemple #14
0
        public bool StartServer()
        {
            if (Listener != null) return false; // Already started

            try
            {
                Log.Info("Initializing...");

                Listener = new UdpClient(_clientEndpoint);

                if (IsRunningOnMono())
                {
                    Listener.Client.ReceiveBufferSize = 1024*1024*3;
                    Listener.Client.SendBufferSize = 4096;
                }
                else
                {
                    Listener.Client.ReceiveBufferSize = int.MaxValue;
                    Listener.Client.SendBufferSize = int.MaxValue;
                    Listener.DontFragment = false;

                    // SIO_UDP_CONNRESET (opcode setting: I, T==3)
                    // Windows:  Controls whether UDP PORT_UNREACHABLE messages are reported.
                    // - Set to TRUE to enable reporting.
                    // - Set to FALSE to disable reporting.

                    uint IOC_IN = 0x80000000;
                    uint IOC_VENDOR = 0x18000000;
                    uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
                    Listener.Client.IOControl((int) SIO_UDP_CONNRESET, new byte[] {Convert.ToByte(false)}, null);

                    ////
                    ////WARNING: We need to catch errors here to remove the code above.
                    ////
                }

                Session = new PlayerNetworkSession(null, _clientEndpoint);

                Listener.BeginReceive(ReceiveCallback, Listener);

                Log.InfoFormat("Server open for business for {0}", Username);

                return true;
            }
            catch (Exception e)
            {
                Log.Error(e);
                StopServer();
            }

            return false;
        }
Exemple #15
0
 private void SendDatagram(PlayerNetworkSession session, Datagram datagram)
 {
     SendDatagram(session.EndPoint, datagram, false);
 }
Exemple #16
0
        public void SendPackage(IPEndPoint senderEndpoint, List<Package> messages, short mtuSize, ref int datagramSequenceNumber, ref int reliableMessageNumber, Reliability reliability = Reliability.Reliable)
        {
            if (messages.Count == 0) return;

            foreach (var message in messages)
            {
                TraceSend(message);
            }

            PlayerNetworkSession session  = new PlayerNetworkSession(null, senderEndpoint);
            Datagram.CreateDatagrams(messages, mtuSize, ref reliableMessageNumber, session, SendDatagram);
        }