예제 #1
0
 public void Setup(int length, NetworkMessageType sendType)
 {
     this.networkMessage = NetworkMessage.Create(-4, length, sendType);
     //Number of chunks needed
     receivePartsLength = (length + 4) / 500;
     if ((length + 4) % 500 > 0)
     {
         receivePartsLength++;
     }
     //Check the send array can fit the chunks
     if (receiveParts == null || receiveParts.Length < receivePartsLength)
     {
         int createLength = 128;
         while (receivePartsLength > createLength)
         {
             createLength = createLength * 4;
         }
         receiveParts = new bool[createLength];
     }
     receivePartsLeft = receivePartsLength;
     for (int i = 0; i < receivePartsLength; i++)
     {
         receiveParts[i] = false;
     }
 }
예제 #2
0
        private void HandleOrdered(ByteArray data, Connection <T> connection)
        {
            if (data.Length < 12)
            {
                return;
            }
            int  orderID  = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data.data, 0));
            int  distance = orderID - connection.receiveOrderID;
            bool orderOK  = false;

            //Normal case
            if ((distance < (Int32.MaxValue / 4)) && distance > 0)
            {
                orderOK = true;
            }
            //Wrap around case
            if (distance < -(Int32.MaxValue / 4))
            {
                orderOK = true;
            }
            if (orderOK)
            {
                connection.receiveOrderID = orderID;
                int            messageType   = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data.data, 4));
                int            messageLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data.data, 8));
                NetworkMessage handleOrdered = NetworkMessage.Create(messageType, messageLength, NetworkMessageType.ORDERED_UNRELIABLE);
                if (messageLength > 0 && messageLength == (data.Length + 12))
                {
                    Array.Copy(data.data, 12, handleOrdered.data.data, 0, messageLength);
                }
                Handle(handleOrdered, connection);
            }
        }
예제 #3
0
        private NetworkMessage ConvertOrderedUnreliableMessage(NetworkMessage input, Connection <T> connection)
        {
            if (input.sendType != NetworkMessageType.ORDERED_UNRELIABLE)
            {
                return(input);
            }
            int newSize = 12;

            if (input.data != null)
            {
                newSize += input.data.Length;
            }
            NetworkMessage converted = NetworkMessage.Create(-3, newSize, NetworkMessageType.UNORDERED_UNRELIABLE);

            DarkUtils.WriteInt32ToByteArray(connection.sendOrderID++, converted.data.data, 0);
            if (connection.sendOrderID == Int32.MaxValue)
            {
                connection.sendOrderID = 0;
            }
            DarkUtils.WriteInt32ToByteArray(input.type, converted.data.data, 4);
            DarkUtils.WriteInt32ToByteArray(newSize - 8, converted.data.data, 8);
            if (input.data != null)
            {
                Array.Copy(input.data.data, 0, converted.data.data, 12, input.data.Length);
            }
            input.Destroy();
            return(input);
        }
예제 #4
0
        internal void HandleRaw(byte[] data, int length, IPEndPoint endPoint)
        {
            if (length < 12)
            {
                return;
            }
            //Magic header, DARK
            if (data[0] != 68 || data[1] != 65 || data[2] != 82 || data[3] != 75)
            {
                return;
            }
            Connection <T> connection   = null;
            Guid           messageOwner = DarkUtils.GuidFromIPEndpoint(endPoint);

            if (!connections.ContainsKey(messageOwner))
            {
                if (connection == null)
                {
                    connection         = new Connection <T>();
                    connection.handler = this;
                    connection.reliableMessageHandler = new ReliableMessageHandler <T>(connection, this);
                    if (network.clientMode && serverConnection == null)
                    {
                        serverConnection = connection;
                    }
                }
                connection.lastReceiveTime = DateTime.UtcNow.Ticks;
                connection.remoteEndpoint  = endPoint;
                lock (connections)
                {
                    connections.Add(messageOwner, connection);
                }
                if (connectCallback != null)
                {
                    connection.state = connectCallback(connection);
                }
            }
            connection = connections[messageOwner];
            int messageType   = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data, 4));
            int messageLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data, 8));

            if (length < messageLength + 12)
            {
                //Malformed message
                return;
            }
            NetworkMessage nm = NetworkMessage.Create(messageType, messageLength, NetworkMessageType.UNORDERED_UNRELIABLE);

            if (nm.data != null && nm.data.Length > 0)
            {
                Array.Copy(data, 12, nm.data.data, 0, nm.data.Length);
            }
            Handle(nm, connection);
        }
예제 #5
0
        private void HandleHeartbeat(ByteArray data, Connection <T> connection)
        {
            if (data.Length != 8)
            {
                return;
            }
            NetworkMessage nm = NetworkMessage.Create(-2, 8, NetworkMessageType.UNORDERED_UNRELIABLE);

            Array.Copy(data.data, 0, nm.data.data, 0, data.Length);
            SendMessageWithHighPriority(nm, connection);
        }
예제 #6
0
        public NetworkMessage Copy()
        {
            NetworkMessage retVal = null;

            if (data != null)
            {
                retVal = NetworkMessage.Create(type, data.size, sendType);
                Array.Copy(data.data, 0, retVal.data.data, 0, data.Length);
            }
            else
            {
                retVal = NetworkMessage.Create(type, 0, sendType);
            }
            return(retVal);
        }
예제 #7
0
        internal void SendHeartbeat()
        {
            lock (connections)
            {
                long currentTime = DateTime.UtcNow.Ticks;
                foreach (KeyValuePair <Guid, Connection <T> > c in connections)
                {
                    if (currentTime > c.Value.lastReceiveTime + TimeSpan.TicksPerSecond * 20)
                    {
                        disconnectList.Add(c.Key);
                    }
                    if (currentTime > (c.Value.lastHeartbeatTime + TimeSpan.TicksPerSecond))
                    {
                        c.Value.lastHeartbeatTime = currentTime;
                        NetworkMessage nm = NetworkMessage.Create(-1, 8, NetworkMessageType.UNORDERED_UNRELIABLE);
                        DarkUtils.WriteInt64ToByteArray(DateTime.UtcNow.Ticks, nm.data.data, 0);
                        SendMessageWithHighPriority(nm, c.Value);
                    }
                    RateControl <T> .Update(c.Value);

                    c.Value.reliableMessageHandler.Send();
                }
                foreach (Guid disconnectConnectionGuid in disconnectList)
                {
                    Connection <T> disconnectConnection = connections[disconnectConnectionGuid];
                    if (disconnectCallback != null)
                    {
                        disconnectCallback(disconnectConnection);
                    }
                    disconnectConnection.reliableMessageHandler.ReleaseAllObjects();
                    network.ReleaseAllObjects(disconnectConnection);
                    connections.Remove(disconnectConnectionGuid);
                }
                disconnectList.Clear();
            }
        }
        public NetworkMessage GetMessage(int id, Connection <T> connection)
        {
            if (finished)
            {
                return(null);
            }
            int checkedThisRound = 0;
            //Always assume at least 10ms lag
            long latency = connection.latency;

            if (latency < 10 * TimeSpan.TicksPerMillisecond)
            {
                latency = 10 * TimeSpan.TicksPerMillisecond;
            }
            //Resend message if it has been 2 RTT's
            long checkTime = DateTime.UtcNow.Ticks - (latency * 2);
            bool found     = false;

            while (!found)
            {
                if (sendParts[nextSendPart] >= 0 && checkTime > sendParts[nextSendPart])
                {
                    found = true;
                }
                else
                {
                    nextSendPart++;
                    if (nextSendPart == sendPartsLength)
                    {
                        nextSendPart = 0;
                    }
                    checkedThisRound++;
                    if (checkedThisRound == sendPartsLength)
                    {
                        //We checked to see if we could send any chunks and didn't find any.
                        break;
                    }
                }
            }
            if (found)
            {
                int totalSize = 4;
                if (networkMessage.data != null)
                {
                    totalSize += networkMessage.data.Length;
                }
                int thisSendSize = 500;
                if (nextSendPart == (sendPartsLength - 1))
                {
                    thisSendSize = totalSize % 500;
                }
                //This is a retransmit, count the lost data
                if (sendParts[nextSendPart] != 0)
                {
                    connection.dataLoss += thisSendSize;
                }
                connection.dataSent += thisSendSize;
                NetworkMessage sendMessage = NetworkMessage.Create(-4, 12 + thisSendSize, NetworkMessageType.UNORDERED_UNRELIABLE);
                DarkUtils.WriteInt32ToByteArray(id, sendMessage.data.data, 0);
                DarkUtils.WriteInt32ToByteArray(nextSendPart, sendMessage.data.data, 4);
                //Don't include the header in the message length, we know it's there
                DarkUtils.WriteInt32ToByteArray(totalSize - 4, sendMessage.data.data, 8);
                if (nextSendPart == 0)
                {
                    DarkUtils.WriteInt32ToByteArray(networkMessage.type, sendMessage.data.data, 12);
                    if (networkMessage.data != null && networkMessage.data.Length > 0)
                    {
                        Array.Copy(networkMessage.data.data, 0, sendMessage.data.data, 16, thisSendSize - 4);
                    }
                }
                else
                {
                    Array.Copy(networkMessage.data.data, (nextSendPart * 500) - 4, sendMessage.data.data, 12, thisSendSize);
                }
                sendParts[nextSendPart] = -2;
                nextSendPart++;
                if (nextSendPart == sendPartsLength)
                {
                    nextSendPart = 0;
                }
                return(sendMessage);
            }
            return(null);
        }
예제 #9
0
        public void Handle(ByteArray data, Connection <T> connection)
        {
            if (connection.destroyed)
            {
                return;
            }
            if (data.Length < 12)
            {
                return;
            }
            int recvSendingID = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data.data, 0));
            int recvPartID    = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data.data, 4));
            int recvLength    = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data.data, 8));
            //Always send an ACK back immediately
            NetworkMessage nm = NetworkMessage.Create(-5, 8, NetworkMessageType.UNORDERED_UNRELIABLE);

            Array.Copy(data.data, 0, nm.data.data, 0, 8);
            handler.SendMessageWithHighPriority(nm, connection);

            ReliableMessageReceiveTracking rmrt = null;

            if (receivingMessages.ContainsKey(recvSendingID))
            {
                rmrt = receivingMessages[recvSendingID];
            }
            //Received either a new chunk or a duplicate, if the messageID is higher than what we have received, it's new.
            if (rmrt == null)
            {
                if (recvSendingID > 0)
                {
                    int distance = recvSendingID - unorderedReceiveID;
                    //A message in the past (doesn't detect wrap around)
                    bool fromThePast = distance <= 0;
                    //A future message received before we have wrapped around
                    bool massivelyInPast = -distance > (Int32.MaxValue / 4);
                    //A past message received when we have wrapped around
                    bool massivelyInFuture = distance > (Int32.MaxValue / 4);
                    if (fromThePast && !massivelyInPast || massivelyInFuture)
                    {
                        return;
                    }
                    while (recvSendingID != unorderedReceiveID)
                    {
                        if (unorderedReceiveID == Int32.MaxValue)
                        {
                            unorderedReceiveID = 0;
                        }
                        unorderedReceiveID++;
                        rmrt = ReliableMessageReceiveTracking.Create();
                        lock (receivingMessages)
                        {
                            receivingMessages.Add(unorderedReceiveID, rmrt);
                        }
                    }
                }
                else
                {
                    int distance = -recvSendingID - orderedReceiveID;
                    //A message in the past (doesn't detect wrap around)
                    bool fromThePast = distance <= 0;
                    //A future message received before we have wrapped around
                    bool massivelyInPast = -distance > (Int32.MaxValue / 4);
                    //A past message received when we have wrapped around
                    bool massivelyInFuture = distance > (Int32.MaxValue / 4);
                    if (fromThePast && !massivelyInPast || massivelyInFuture)
                    {
                        return;
                    }
                    while (-recvSendingID != orderedReceiveID)
                    {
                        if (orderedReceiveID == Int32.MaxValue)
                        {
                            orderedReceiveID = 0;
                        }
                        orderedReceiveID++;
                        rmrt = ReliableMessageReceiveTracking.Create();
                        lock (receivingMessages)
                        {
                            receivingMessages.Add(-orderedReceiveID, rmrt);
                        }
                    }
                }
                rmrt = receivingMessages[recvSendingID];
            }

            //Fist setup if needed
            if (rmrt.networkMessage == null)
            {
                if (recvSendingID > 0)
                {
                    rmrt.Setup(recvLength, NetworkMessageType.UNORDERED_RELIABLE);
                }
                else
                {
                    rmrt.Setup(recvLength, NetworkMessageType.ORDERED_RELIABLE);
                }
            }

            //Handle incoming data
            rmrt.Handle(recvPartID, recvLength, data);

            //We have all the parts
            if (rmrt.receivePartsLeft == 0)
            {
                if (recvSendingID > 0)
                {
                    handler.Handle(rmrt.networkMessage, connection);
                }
                else
                {
                    //This message is received in order
                    if (-recvSendingID == orderedHandleID)
                    {
                        orderedHandleID++;
                        if (orderedHandleID == Int32.MaxValue)
                        {
                            orderedHandleID = 0;
                        }
                        handler.Handle(rmrt.networkMessage, connection);
                    }
                    else
                    {
                        //This message is received out of order and we need to hold onto it
                        orderedHandleMessages.Add(-recvSendingID, rmrt.networkMessage);
                    }
                    //If a message fills the missing hole this can play out.
                    while (orderedHandleMessages.ContainsKey(orderedHandleID))
                    {
                        NetworkMessage handleMessage = orderedHandleMessages[orderedHandleID];
                        orderedHandleMessages.Remove(orderedHandleID);
                        handler.Handle(handleMessage, connection);
                        orderedHandleID++;
                        if (orderedHandleID == Int32.MaxValue)
                        {
                            orderedHandleID = 0;
                        }
                    }
                }
                rmrt.Destroy();
                lock (receivingMessages)
                {
                    receivingMessages.Remove(recvSendingID);
                }
            }
        }