Exemple #1
0
        private async Task SendAckQueueAsync()
        {
            RakSession session    = this;
            var        queue      = session.OutgoingAckQueue;
            int        queueCount = queue.Count;

            if (queueCount == 0)
            {
                return;
            }

            var acks = Acks.CreateObject();

            for (int i = 0; i < queueCount; i++)
            {
                if (!queue.TryDequeue(out int ack))
                {
                    break;
                }

                Interlocked.Increment(ref ConnectionInfo.NumberOfAckSent);
                acks.acks.Add(ack);
            }

            if (acks.acks.Count > 0)
            {
                byte[] data = acks.Encode();
                await _packetSender.SendDataAsync(data, session.EndPoint);
            }

            acks.PutPool();
        }
Exemple #2
0
        public static void HandleRakNetMessage(MiNetServer server, IPEndPoint senderEndpoint, OpenConnectionRequest2 incoming)
        {
            RakSession session;

            lock (server._rakNetSessions)
            {
                if (!server._connectionAttemps.TryRemove(senderEndpoint, out _))
                {
                    Log.WarnFormat("Unexpected connection request packet from {0}. Probably a resend.", senderEndpoint.Address);
                    return;
                }

                if (server._rakNetSessions.TryGetValue(senderEndpoint, out session))
                {
                    // Already connecting, then this is just a duplicate
                    if (session.State == ConnectionState.Connecting /* && DateTime.UtcNow < session.LastUpdatedTime + TimeSpan.FromSeconds(2)*/)
                    {
                        return;
                    }

                    Log.InfoFormat("Unexpected session from {0}. Removing old session and disconnecting old player.", senderEndpoint.Address);

                    session.Disconnect("Reconnecting.", false);

                    server._rakNetSessions.TryRemove(senderEndpoint, out _);
                }

                session = new RakSession(server, null, senderEndpoint, incoming.mtuSize)
                {
                    State             = ConnectionState.Connecting,
                    LastUpdatedTime   = DateTime.UtcNow,
                    MtuSize           = incoming.mtuSize,
                    NetworkIdentifier = incoming.clientGuid
                };

                server._rakNetSessions.TryAdd(senderEndpoint, session);
            }

            session.MessageHandler = new LoginMessageHandler(session);

            var reply = OpenConnectionReply2.CreateObject();

            reply.serverGuid             = server.MotdProvider.ServerId;
            reply.clientEndpoint         = senderEndpoint;
            reply.mtuSize                = incoming.mtuSize;
            reply.doSecurityAndHandshake = new byte[1];
            byte[] data = reply.Encode();

            TraceSend(reply);

            reply.PutPool();

            server.SendData(data, senderEndpoint);
        }
Exemple #3
0
        private void HandleRakNetMessage(IPEndPoint senderEndpoint, OpenConnectionRequest2 incoming)
        {
            ConcurrentDictionary <IPEndPoint, RakSession> sessions           = _connectionInfo.RakSessions;
            ConcurrentDictionary <IPEndPoint, DateTime>   connectionAttempts = _connectionAttempts;

            lock (sessions)
            {
                if (!connectionAttempts.ContainsKey(senderEndpoint))
                {
                    Log.Warn($"Unexpected connection request packet from {senderEndpoint}. Probably a resend.");
                    return;
                }

                if (sessions.TryGetValue(senderEndpoint, out _))
                {
                    Log.Warn($"Trying to create session where session already exist. Please wait for timeout on {senderEndpoint}. Ignoring this request.");
                    return;
                }

                var session = new RakSession(_connectionInfo, _sender, senderEndpoint, incoming.mtuSize)
                {
                    State             = ConnectionState.Connecting,
                    LastUpdatedTime   = DateTime.UtcNow,
                    MtuSize           = incoming.mtuSize,
                    NetworkIdentifier = incoming.clientGuid,
                };

                session.CustomMessageHandler = _connection.CustomMessageHandlerFactory?.Invoke(session);

                sessions.TryAdd(senderEndpoint, session);
            }

            var reply = OpenConnectionReply2.CreateObject();

            reply.serverGuid             = _motdProvider.ServerId;
            reply.clientEndpoint         = senderEndpoint;
            reply.mtuSize                = incoming.mtuSize;
            reply.doSecurityAndHandshake = new byte[1];
            byte[] data = reply.Encode();

            TraceSend(reply);

            reply.PutPool();

            _sender.SendData(data, senderEndpoint);
        }
Exemple #4
0
        private void SendConnectionRequest(IPEndPoint targetEndPoint, short mtuSize)
        {
            ConcurrentDictionary <IPEndPoint, RakSession> sessions = _connectionInfo.RakSessions;

            RakSession session;

            lock (sessions)
            {
                if (sessions.ContainsKey(targetEndPoint))
                {
                    Log.Debug($"Session already exist, ignoring");
                    return;
                }

                session = new RakSession(_connectionInfo, _sender, targetEndPoint, mtuSize)
                {
                    State             = ConnectionState.Connecting,
                    LastUpdatedTime   = DateTime.UtcNow,
                    NetworkIdentifier = ClientGuid,
                };

                session.CustomMessageHandler = _connection.CustomMessageHandlerFactory?.Invoke(session);

                if (!sessions.TryAdd(targetEndPoint, session))
                {
                    Log.Debug($"Session already exist, ignoring");
                    return;
                }
            }

            var packet = ConnectionRequest.CreateObject();

            packet.clientGuid = ClientGuid;
            packet.timestamp  = DateTime.UtcNow.Ticks;
            packet.doSecurity = 0;

            session.SendPacket(packet);
        }
Exemple #5
0
        private static List <MessagePart> CreateMessageParts(Packet message, int mtuSize, RakSession session)
        {
            Memory <byte> encodedMessage = message.Encode();

            if (encodedMessage.IsEmpty)
            {
                return(new List <MessagePart>(0));
            }

            if (message.IsMcpe)
            {
                Log.Error($"Got bedrock message in unexpected place {message.GetType().Name}");
            }

            int  maxPayloadSizeNoSplit = mtuSize - 28 - GetHeaderSize(message.ReliabilityHeader, false);
            bool split = encodedMessage.Length >= maxPayloadSizeNoSplit;

            List <(int @from, int length)> splits = ArraySplit(encodedMessage.Length, mtuSize - RakOfflineHandler.UdpHeaderSize - 4 /*datagram header*/ - GetHeaderSize(message.ReliabilityHeader, split));
            int count = splits.Count;

            if (count == 0)
            {
                Log.Warn("Got zero parts back from split");
            }
            if (count <= 1)
            {
                var messagePart = MessagePart.CreateObject();
                messagePart.ReliabilityHeader.Reliability           = message.ReliabilityHeader.Reliability;
                messagePart.ReliabilityHeader.ReliableMessageNumber = Interlocked.Increment(ref session.ReliableMessageNumber);
                messagePart.ReliabilityHeader.OrderingChannel       = 0;
                messagePart.ReliabilityHeader.OrderingIndex         = message.ReliabilityHeader.OrderingIndex;
                messagePart.ReliabilityHeader.HasSplit = false;
                messagePart.Buffer = encodedMessage;

                return(new List <MessagePart>(1)
                {
                    messagePart
                });
            }

            // Stupid but scared to change it .. remove the -100 when i feel "safe"
            if (session.SplitPartId > short.MaxValue - 100)
            {
                Interlocked.CompareExchange(ref session.SplitPartId, 0, short.MaxValue);
            }

            int   index        = 0;
            short splitId      = (short)Interlocked.Increment(ref session.SplitPartId);
            var   messageParts = new List <MessagePart>(count);

            foreach ((int from, int length)span in splits)
            {
                var messagePart = MessagePart.CreateObject();
                messagePart.ReliabilityHeader.Reliability           = message.ReliabilityHeader.Reliability;
                messagePart.ReliabilityHeader.ReliableMessageNumber = Interlocked.Increment(ref session.ReliableMessageNumber);
                messagePart.ReliabilityHeader.OrderingChannel       = 0;
                messagePart.ReliabilityHeader.OrderingIndex         = message.ReliabilityHeader.OrderingIndex;
                messagePart.ReliabilityHeader.HasSplit  = count > 1;
                messagePart.ReliabilityHeader.PartCount = count;
                messagePart.ReliabilityHeader.PartId    = splitId;
                messagePart.ReliabilityHeader.PartIndex = index++;
                messagePart.Buffer = encodedMessage.Slice(span.@from, span.length);

                messageParts.Add(messagePart);
            }

            return(messageParts);
        }
Exemple #6
0
        public static IEnumerable <Datagram> CreateDatagrams(Packet message, int mtuSize, RakSession session)
        {
            Datagram datagram = CreateObject();

            List <MessagePart> messageParts = CreateMessageParts(message, mtuSize, session);

            foreach (MessagePart 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 #7
0
        private static List <MessagePart> CreateMessageParts(Packet message, int mtuSize, Reliability reliability, RakSession session)
        {
            Memory <byte> encodedMessage = message.Encode();

            if (encodedMessage.IsEmpty)
            {
                return(new List <MessagePart>(0));
            }

            // All MCPE messages goes into a compressed (and possible encrypted) wrapper.
            // Note that McpeWrapper itself is a RakNet level message.
            bool isWrapper = message is McpeWrapper;

            if (message.IsMcpe)
            {
                var wrapper = McpeWrapper.CreateObject();
                wrapper.payload = Compression.Compress(encodedMessage, true, encodedMessage.Length > 1000 ? CompressionLevel.Fastest : CompressionLevel.NoCompression);
                encodedMessage  = wrapper.Encode();
                wrapper.PutPool();
                isWrapper = true;
            }

            // Should probably only force for McpeWrapper, not the other messages (RakNet)
            if (!(message is ConnectedPong) && !(message is DetectLostConnections))
            {
                reliability = Reliability.ReliableOrdered;
            }

            int orderingIndex = 0;

            lock (session.EncodeSync)
            {
                CryptoContext cryptoContext = session.CryptoContext;
                if (!message.ForceClear && cryptoContext != null && session.CryptoContext.UseEncryption && isWrapper)
                {
                    var wrapper = McpeWrapper.CreateObject();
                    wrapper.payload = CryptoUtils.Encrypt(encodedMessage.Slice(1), cryptoContext);
                    encodedMessage  = wrapper.Encode();
                    wrapper.PutPool();
                }

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

            List <(int @from, int length)> splits = ArraySplit(encodedMessage.Length, mtuSize - 100);
            int count = splits.Count;

            if (count == 0)
            {
                Log.Warn("Got zero parts back from split");
            }
            if (count <= 1)
            {
                var messagePart = MessagePart.CreateObject();
                messagePart.ReliabilityHeader.Reliability           = reliability;
                messagePart.ReliabilityHeader.ReliableMessageNumber = Interlocked.Increment(ref session.ReliableMessageNumber);
                messagePart.ReliabilityHeader.OrderingChannel       = 0;
                messagePart.ReliabilityHeader.OrderingIndex         = orderingIndex;
                messagePart.ReliabilityHeader.HasSplit = false;
                messagePart.Buffer = encodedMessage;

                return(new List <MessagePart>(1)
                {
                    messagePart
                });
            }

            // Stupid but scared to change it .. remove the -100 when i feel "safe"
            if (session.SplitPartId > short.MaxValue - 100)
            {
                Interlocked.CompareExchange(ref session.SplitPartId, 0, short.MaxValue);
            }

            int   index        = 0;
            short splitId      = (short)Interlocked.Increment(ref session.SplitPartId);
            var   messageParts = new List <MessagePart>(count);

            foreach ((int from, int length)span in splits)
            {
                var messagePart = MessagePart.CreateObject();
                messagePart.ReliabilityHeader.Reliability           = reliability;
                messagePart.ReliabilityHeader.ReliableMessageNumber = Interlocked.Increment(ref session.ReliableMessageNumber);
                messagePart.ReliabilityHeader.OrderingChannel       = 0;
                messagePart.ReliabilityHeader.OrderingIndex         = orderingIndex;
                messagePart.ReliabilityHeader.HasSplit  = count > 1;
                messagePart.ReliabilityHeader.PartCount = count;
                messagePart.ReliabilityHeader.PartId    = splitId;
                messagePart.ReliabilityHeader.PartIndex = index++;
                messagePart.Buffer = encodedMessage.Slice(span.@from, span.length);

                messageParts.Add(messagePart);
            }

            return(messageParts);
        }