From 330c5cf83e76565eb415919cefe7d9276e77c50d Mon Sep 17 00:00:00 2001 From: lidgren Date: Mon, 20 Dec 2010 10:35:51 +0000 Subject: [PATCH] ConnectionLatencyUpdated message type added; WriteTime() ReadTime() added --- Lidgren.Network/NetConnection.Handshake.cs | 3 +- Lidgren.Network/NetConnection.Latency.cs | 42 ++++++++++++++++----- Lidgren.Network/NetConnection.MTU.cs | 2 +- Lidgren.Network/NetConnection.cs | 12 +++--- Lidgren.Network/NetIncomingMessage.Read.cs | 14 +++++++ Lidgren.Network/NetIncomingMessage.cs | 6 +++ Lidgren.Network/NetIncomingMessageType.cs | 1 + Lidgren.Network/NetOutgoingMessage.Write.cs | 11 ++++++ Lidgren.Network/NetPeer.Fragmentation.cs | 2 +- Lidgren.Network/NetPeer.Internal.cs | 15 ++++---- Lidgren.Network/NetPeerConfiguration.cs | 2 +- 11 files changed, 85 insertions(+), 25 deletions(-) diff --git a/Lidgren.Network/NetConnection.Handshake.cs b/Lidgren.Network/NetConnection.Handshake.cs index a9fee3e..612c027 100644 --- a/Lidgren.Network/NetConnection.Handshake.cs +++ b/Lidgren.Network/NetConnection.Handshake.cs @@ -183,7 +183,7 @@ namespace Lidgren.Network m_peer.m_handshakes.Remove(m_remoteEndpoint); // TODO: make this more thread safe? we're on user thread } - internal void ReceivedHandshake(NetMessageType tp, int ptr, int payloadLength) + internal void ReceivedHandshake(double now, NetMessageType tp, int ptr, int payloadLength) { m_peer.VerifyNetworkThread(); @@ -211,6 +211,7 @@ namespace Lidgren.Network { // ok, let's not add connection just yet NetIncomingMessage appMsg = m_peer.CreateIncomingMessage(NetIncomingMessageType.ConnectionApproval, (m_remoteHailMessage == null ? 0 : m_remoteHailMessage.LengthBytes)); + appMsg.m_receiveTime = now; appMsg.m_senderConnection = this; appMsg.m_senderEndpoint = this.m_remoteEndpoint; if (m_remoteHailMessage != null) diff --git a/Lidgren.Network/NetConnection.Latency.cs b/Lidgren.Network/NetConnection.Latency.cs index f6e9bd2..ca832d4 100644 --- a/Lidgren.Network/NetConnection.Latency.cs +++ b/Lidgren.Network/NetConnection.Latency.cs @@ -9,11 +9,19 @@ namespace Lidgren.Network private float m_averageRoundtripTime; private float m_timeoutDeadline = float.MaxValue; + // local time value + m_remoteTimeOffset = remote time value + internal double m_remoteTimeOffset; + /// /// Gets the current average roundtrip time in seconds /// public float AverageRoundtripTime { get { return m_averageRoundtripTime; } } + internal double GetLocalTime(double remoteTimeStamp) + { + return remoteTimeStamp - m_remoteTimeOffset; + } + internal void InitializePing() { // randomize ping sent time (0.25 - 1.0 x ping interval) @@ -27,11 +35,10 @@ namespace Lidgren.Network m_peer.VerifyNetworkThread(); m_sentPingNumber++; - if (m_sentPingNumber >= 256) - m_sentPingNumber = 0; + m_sentPingTime = (float)NetTime.Now; NetOutgoingMessage om = m_peer.CreateMessage(1); - om.Write((byte)m_sentPingNumber); + om.Write((byte)m_sentPingNumber); // truncating to 0-255 om.m_messageType = NetMessageType.Ping; int len = om.Encode(m_peer.m_sendBuffer, 0, 0); @@ -45,20 +52,22 @@ namespace Lidgren.Network { m_peer.VerifyNetworkThread(); - NetOutgoingMessage om = m_peer.CreateMessage(1); + NetOutgoingMessage om = m_peer.CreateMessage(5); om.Write((byte)pingNumber); + om.Write((float)NetTime.Now); // we should update this value to reflect the exact point in time the packet is SENT om.m_messageType = NetMessageType.Pong; int len = om.Encode(m_peer.m_sendBuffer, 0, 0); bool connectionReset; + m_peer.SendPacket(len, m_remoteEndpoint, 1, out connectionReset); m_statistics.PacketSent(len, 1); } - internal void ReceivedPong(float now, int pongNumber) + internal void ReceivedPong(float now, int pongNumber, float remoteSendTime) { - if (pongNumber != m_sentPingNumber) + if ((byte)pongNumber != (byte)m_sentPingNumber) { m_peer.LogVerbose("Ping/Pong mismatch; dropped message?"); return; @@ -69,15 +78,20 @@ namespace Lidgren.Network float rtt = now - m_sentPingTime; NetException.Assert(rtt >= 0); + double diff = (remoteSendTime + (rtt / 2.0)) - now; + if (m_averageRoundtripTime < 0) { + m_remoteTimeOffset = diff; m_averageRoundtripTime = rtt; // initial estimate - m_peer.LogDebug("Initiated average roundtrip time to " + NetTime.ToReadable(m_averageRoundtripTime)); + m_peer.LogDebug("Initiated average roundtrip time to " + NetTime.ToReadable(m_averageRoundtripTime) + " Server time is: " + (now + diff)); } else { m_averageRoundtripTime = (m_averageRoundtripTime * 0.7f) + (float)(rtt * 0.3f); - m_peer.LogVerbose("Updated average roundtrip time to " + NetTime.ToReadable(m_averageRoundtripTime)); + + m_remoteTimeOffset = ((m_remoteTimeOffset * (double)(m_sentPingNumber - 1)) + diff) / (double)m_sentPingNumber; + m_peer.LogVerbose("Updated average roundtrip time to " + NetTime.ToReadable(m_averageRoundtripTime) + ", server time to " + (now + m_remoteTimeOffset) + " (ie. diff " + m_remoteTimeOffset + ")"); } // update resend delay for all channels @@ -89,7 +103,17 @@ namespace Lidgren.Network rchan.m_resendDelay = resendDelay; } - m_peer.LogVerbose("Timeout deadline pushed to " + m_timeoutDeadline); + // m_peer.LogVerbose("Timeout deadline pushed to " + m_timeoutDeadline); + + // notify the application that average rtt changed + if (m_peer.m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.ConnectionLatencyUpdated)) + { + NetIncomingMessage update = m_peer.CreateIncomingMessage(NetIncomingMessageType.ConnectionLatencyUpdated, 4); + update.m_senderConnection = this; + update.m_senderEndpoint = this.m_remoteEndpoint; + update.Write(rtt); + m_peer.ReleaseMessage(update); + } } } } diff --git a/Lidgren.Network/NetConnection.MTU.cs b/Lidgren.Network/NetConnection.MTU.cs index 4818a55..28ff6c4 100644 --- a/Lidgren.Network/NetConnection.MTU.cs +++ b/Lidgren.Network/NetConnection.MTU.cs @@ -26,7 +26,7 @@ namespace Lidgren.Network internal void InitExpandMTU(double now) { - m_lastSentMTUAttemptTime = now + m_peerConfiguration.m_expandMTUFrequency + 1.0f; // wait a tiny bit before starting to expand mtu + m_lastSentMTUAttemptTime = now + m_peerConfiguration.m_expandMTUFrequency + 1.5f + m_averageRoundtripTime; // wait a tiny bit before starting to expand mtu m_largestSuccessfulMTU = 512; m_smallestFailedMTU = -1; m_currentMTU = m_peerConfiguration.MaximumTransmissionUnit; diff --git a/Lidgren.Network/NetConnection.cs b/Lidgren.Network/NetConnection.cs index dcffbc2..d5916b1 100644 --- a/Lidgren.Network/NetConnection.cs +++ b/Lidgren.Network/NetConnection.cs @@ -138,10 +138,10 @@ namespace Lidgren.Network { if (now > m_sentPingTime + m_peer.m_configuration.m_pingInterval) SendPing(); - } - // handle expand mtu - MTUExpansionHeartbeat(now); + // handle expand mtu + MTUExpansionHeartbeat(now); + } if (m_disconnectRequested) { @@ -352,8 +352,10 @@ namespace Lidgren.Network SendPong(pingNr); break; case NetMessageType.Pong: - int pongNr = m_peer.m_receiveBuffer[ptr++]; - ReceivedPong(now, pongNr); + NetIncomingMessage pmsg = m_peer.SetupReadHelperMessage(ptr, payloadLength); + int pongNr = pmsg.ReadByte(); + float remoteSendTime = pmsg.ReadSingle(); + ReceivedPong(now, pongNr, remoteSendTime); break; case NetMessageType.ExpandMTURequest: SendMTUSuccess(payloadLength); diff --git a/Lidgren.Network/NetIncomingMessage.Read.cs b/Lidgren.Network/NetIncomingMessage.Read.cs index d242514..5160b7b 100644 --- a/Lidgren.Network/NetIncomingMessage.Read.cs +++ b/Lidgren.Network/NetIncomingMessage.Read.cs @@ -465,6 +465,20 @@ namespace Lidgren.Network return new IPEndPoint(address, port); } + /// + /// Reads a value, in local time comparable to NetTime.Now, written using WriteTime() + /// Must have a connected sender + /// + public double ReadTime(bool highPrecision) + { + double remoteTime = (highPrecision ? ReadDouble() : (double)ReadSingle()); + + if (m_senderConnection == null) + throw new NetException("Cannot call ReadTime() on message without a connected sender (ie. unconnected messages)"); + + return remoteTime - m_senderConnection.m_remoteTimeOffset; + } + /// /// Pads data with enough bits to reach a full byte. Decreases cpu usage for subsequent byte writes. /// diff --git a/Lidgren.Network/NetIncomingMessage.cs b/Lidgren.Network/NetIncomingMessage.cs index a75f0b3..f10f326 100644 --- a/Lidgren.Network/NetIncomingMessage.cs +++ b/Lidgren.Network/NetIncomingMessage.cs @@ -36,6 +36,7 @@ namespace Lidgren.Network internal int m_sequenceNumber; internal NetMessageType m_receivedMessageType; internal bool m_isFragment; + internal double m_receiveTime; /// /// Gets the type of this incoming message @@ -62,6 +63,11 @@ namespace Lidgren.Network /// public NetConnection SenderConnection { get { return m_senderConnection; } } + /// + /// What local time the message was received from the network + /// + public double ReceiveTime { get { return m_receiveTime; } } + /// /// Gets the length of the message payload in bytes /// diff --git a/Lidgren.Network/NetIncomingMessageType.cs b/Lidgren.Network/NetIncomingMessageType.cs index 99d0cc5..b05cd56 100644 --- a/Lidgren.Network/NetIncomingMessageType.cs +++ b/Lidgren.Network/NetIncomingMessageType.cs @@ -42,5 +42,6 @@ namespace Lidgren.Network WarningMessage = 1 << 9, // Data (string) ErrorMessage = 1 << 10, // Data (string) NatIntroductionSuccess = 1 << 11, // Data (as passed to master server) + ConnectionLatencyUpdated = 1 << 12, // Seconds as a Single } } diff --git a/Lidgren.Network/NetOutgoingMessage.Write.cs b/Lidgren.Network/NetOutgoingMessage.Write.cs index 07a1711..3312dad 100644 --- a/Lidgren.Network/NetOutgoingMessage.Write.cs +++ b/Lidgren.Network/NetOutgoingMessage.Write.cs @@ -534,6 +534,17 @@ namespace Lidgren.Network Write((ushort)endPoint.Port); } + /// + /// Writes the local time to a message; readable (and convertable to local time) by the remote host using ReadTime() + /// + public void WriteTime(double localTime, bool highPrecision) + { + if (highPrecision) + Write(localTime); + else + Write((float)localTime); + } + /// /// Pads data with enough bits to reach a full byte. Decreases cpu usage for subsequent byte writes. /// diff --git a/Lidgren.Network/NetPeer.Fragmentation.cs b/Lidgren.Network/NetPeer.Fragmentation.cs index 0eed9ab..08027f6 100644 --- a/Lidgren.Network/NetPeer.Fragmentation.cs +++ b/Lidgren.Network/NetPeer.Fragmentation.cs @@ -124,7 +124,7 @@ namespace Lidgren.Network Buffer.BlockCopy(im.m_data, ptr, info.Data, offset, im.LengthBytes - ptr); int cnt = info.ReceivedChunks.Count(); - //Console.WriteLine("Found fragment #" + chunkNumber + " in group " + group + " offset " + offset + " of total bits " + totalBits + " (total chunks done " + cnt + ")"); + //LogVerbose("Found fragment #" + chunkNumber + " in group " + group + " offset " + offset + " of total bits " + totalBits + " (total chunks done " + cnt + ")"); LogVerbose("Received fragment " + chunkNumber + " of " + totalNumChunks + " (" + cnt + " chunks received)"); diff --git a/Lidgren.Network/NetPeer.Internal.cs b/Lidgren.Network/NetPeer.Internal.cs index 983b943..3dd5750 100644 --- a/Lidgren.Network/NetPeer.Internal.cs +++ b/Lidgren.Network/NetPeer.Internal.cs @@ -43,9 +43,6 @@ namespace Lidgren.Network { NetException.Assert(msg.m_incomingMessageType != NetIncomingMessageType.Error); - if (msg.MessageType == NetIncomingMessageType.UnconnectedData) - Console.WriteLine("x"); - if (msg.m_isFragment) { HandleReleasedFragment(msg); @@ -306,6 +303,7 @@ namespace Lidgren.Network NetConnection sender = null; m_connectionLookup.TryGetValue(ipsender, out sender); + double receiveTime = NetTime.Now; // // parse packet into messages // @@ -344,7 +342,7 @@ namespace Lidgren.Network if (sender != null) sender.ReceivedLibraryMessage(tp, ptr, payloadByteLength); else - ReceivedUnconnectedLibraryMessage(ipsender, tp, ptr, payloadByteLength); + ReceivedUnconnectedLibraryMessage(receiveTime, ipsender, tp, ptr, payloadByteLength); } else { @@ -353,6 +351,7 @@ namespace Lidgren.Network NetIncomingMessage msg = CreateIncomingMessage(NetIncomingMessageType.Data, payloadByteLength); msg.m_isFragment = isFragment; + msg.m_receiveTime = receiveTime; msg.m_sequenceNumber = sequenceNumber; msg.m_receivedMessageType = tp; msg.m_senderConnection = sender; @@ -390,12 +389,12 @@ namespace Lidgren.Network } } - private void ReceivedUnconnectedLibraryMessage(IPEndPoint senderEndpoint, NetMessageType tp, int ptr, int payloadByteLength) + private void ReceivedUnconnectedLibraryMessage(double now, IPEndPoint senderEndpoint, NetMessageType tp, int ptr, int payloadByteLength) { NetConnection shake; if (m_handshakes.TryGetValue(senderEndpoint, out shake)) { - shake.ReceivedHandshake(tp, ptr, payloadByteLength); + shake.ReceivedHandshake(now, tp, ptr, payloadByteLength); return; } @@ -410,6 +409,7 @@ namespace Lidgren.Network NetIncomingMessage dm = CreateIncomingMessage(NetIncomingMessageType.DiscoveryRequest, payloadByteLength); if (payloadByteLength > 0) Buffer.BlockCopy(m_receiveBuffer, ptr, dm.m_data, 0, payloadByteLength); + dm.m_receiveTime = now; dm.m_bitLength = payloadByteLength * 8; dm.m_senderEndpoint = senderEndpoint; ReleaseMessage(dm); @@ -422,6 +422,7 @@ namespace Lidgren.Network NetIncomingMessage dr = CreateIncomingMessage(NetIncomingMessageType.DiscoveryResponse, payloadByteLength); if (payloadByteLength > 0) Buffer.BlockCopy(m_receiveBuffer, ptr, dr.m_data, 0, payloadByteLength); + dr.m_receiveTime = now; dr.m_bitLength = payloadByteLength * 8; dr.m_senderEndpoint = senderEndpoint; ReleaseMessage(dr); @@ -460,7 +461,7 @@ namespace Lidgren.Network // Ok, start handshake! NetConnection conn = new NetConnection(this, senderEndpoint); m_handshakes.Add(senderEndpoint, conn); - conn.ReceivedHandshake(tp, ptr, payloadByteLength); + conn.ReceivedHandshake(now, tp, ptr, payloadByteLength); return; } diff --git a/Lidgren.Network/NetPeerConfiguration.cs b/Lidgren.Network/NetPeerConfiguration.cs index 0755f5f..f6748b3 100644 --- a/Lidgren.Network/NetPeerConfiguration.cs +++ b/Lidgren.Network/NetPeerConfiguration.cs @@ -67,7 +67,7 @@ namespace Lidgren.Network // // default values // - m_disabledTypes = NetIncomingMessageType.ConnectionApproval | NetIncomingMessageType.UnconnectedData | NetIncomingMessageType.VerboseDebugMessage; + m_disabledTypes = NetIncomingMessageType.ConnectionApproval | NetIncomingMessageType.UnconnectedData | NetIncomingMessageType.VerboseDebugMessage | NetIncomingMessageType.ConnectionLatencyUpdated; m_networkThreadName = "Lidgren network thread"; m_localAddress = IPAddress.Any; m_port = 0;