From 609bc1afe2061e29aa12d2fa984d3b5850b9ffbc Mon Sep 17 00:00:00 2001 From: lidgren Date: Tue, 19 Oct 2010 17:45:55 +0000 Subject: [PATCH] major update; gen 3.5 --- Lidgren.Network/NetBitVector.cs | 51 +- Lidgren.Network/NetClient.cs | 21 +- Lidgren.Network/NetConnection.Handshake.cs | 518 +++++---- Lidgren.Network/NetConnection.Latency.cs | 168 +-- Lidgren.Network/NetConnection.cs | 1019 +++++------------ Lidgren.Network/NetConnectionStatistics.cs | 64 +- Lidgren.Network/NetConnectionStatus.cs | 10 +- Lidgren.Network/NetConstants.cs | 26 +- Lidgren.Network/NetDeliveryMethod.cs | 23 + Lidgren.Network/NetEncryption.cs | 193 +--- Lidgren.Network/NetException.cs | 4 +- Lidgren.Network/NetFragmentationHelper.cs | 174 +++ Lidgren.Network/NetIncomingMessage.Peek.cs | 2 +- .../NetIncomingMessage.Read.Reflection.cs | 43 +- Lidgren.Network/NetIncomingMessage.Read.cs | 8 +- Lidgren.Network/NetIncomingMessage.Stream.cs | 65 -- Lidgren.Network/NetIncomingMessage.Write.cs | 7 +- Lidgren.Network/NetIncomingMessage.cs | 124 +- Lidgren.Network/NetIncomingMessageType.cs | 2 +- Lidgren.Network/NetMessageType.cs | 297 ++--- Lidgren.Network/NetNatIntroduction.cs | 23 +- Lidgren.Network/NetOutgoingMessage.Stream.cs | 52 - .../NetOutgoingMessage.Write.Reflection.cs | 4 +- Lidgren.Network/NetOutgoingMessage.Write.cs | 2 +- Lidgren.Network/NetOutgoingMessage.cs | 211 ++-- Lidgren.Network/NetPeer.Discovery.cs | 31 +- Lidgren.Network/NetPeer.Fragmentation.cs | 150 +++ Lidgren.Network/NetPeer.Internal.cs | 764 +++++------- Lidgren.Network/NetPeer.LatencySimulation.cs | 98 +- Lidgren.Network/NetPeer.MessagePools.cs | 194 ++++ Lidgren.Network/NetPeer.Send.cs | 154 +++ Lidgren.Network/NetPeer.cs | 392 ++----- Lidgren.Network/NetPeerConfiguration.cs | 298 ++--- Lidgren.Network/NetPeerStatistics.cs | 9 +- Lidgren.Network/NetPeerStatus.cs | 3 + Lidgren.Network/NetQueue.cs | 13 +- Lidgren.Network/NetRandom.cs | 367 +++--- Lidgren.Network/NetReceiverChannelBase.cs | 18 + Lidgren.Network/NetReliableOrderedReceiver.cs | 87 ++ Lidgren.Network/NetReliableSenderChannel.cs | 236 ++++ .../NetReliableSequencedReceiver.cs | 63 + .../NetReliableUnorderedReceiver.cs | 87 ++ Lidgren.Network/NetSendResult.cs | 30 + Lidgren.Network/NetSenderChannelBase.cs | 19 + Lidgren.Network/NetSending.cs | 55 - Lidgren.Network/NetServer.cs | 33 +- Lidgren.Network/NetStoredReliableMessage.cs | 18 + Lidgren.Network/NetTime.cs | 4 - Lidgren.Network/NetTuple.cs | 20 + Lidgren.Network/NetUnreliableSenderChannel.cs | 125 ++ .../NetUnreliableSequencedReceiver.cs | 29 + .../NetUnreliableUnorderedReceiver.cs | 20 + Lidgren.Network/NetUtility.cs | 60 +- Lidgren.Network/SenderChannelBase.cs | 11 + .../BarebonesClient/BarebonesClient.csproj | 58 - Samples/BarebonesClient/Program.cs | 72 -- .../Properties/AssemblyInfo.cs | 36 - .../BarebonesServer/BarebonesServer.csproj | 58 - Samples/BarebonesServer/Program.cs | 66 -- .../Properties/AssemblyInfo.cs | 36 - Samples/Chat/Chat.sln | 57 + .../{ => Chat}/ChatClient/ChatClient.csproj | 15 +- .../{ => Chat}/ChatClient/Form1.Designer.cs | 90 +- Samples/Chat/ChatClient/Form1.cs | 70 ++ Samples/{ => Chat}/ChatClient/Form1.resx | 0 Samples/Chat/ChatClient/Program.cs | 115 ++ .../ChatClient/Properties/AssemblyInfo.cs | 2 +- .../Properties/Resources.Designer.cs | 2 +- .../ChatClient/Properties/Resources.resx | 0 .../Properties/Settings.Designer.cs | 2 +- .../ChatClient/Properties/Settings.settings | 0 .../{ => Chat}/ChatServer/ChatServer.csproj | 15 +- Samples/Chat/ChatServer/Form1.Designer.cs | 128 +++ Samples/Chat/ChatServer/Form1.cs | 35 + Samples/{ => Chat}/ChatServer/Form1.resx | 0 Samples/Chat/ChatServer/Program.cs | 126 ++ .../ChatServer/Properties/AssemblyInfo.cs | 2 +- .../Properties/Resources.Designer.cs | 2 +- .../ChatServer/Properties/Resources.resx | 0 .../Properties/Settings.Designer.cs | 2 +- .../ChatServer/Properties/Settings.settings | 0 Samples/ChatClient/Form1.cs | 49 - Samples/ChatClient/Program.cs | 109 -- Samples/ChatServer/Form1.Designer.cs | 77 -- Samples/ChatServer/Form1.cs | 30 - Samples/ChatServer/Program.cs | 92 -- Samples/DurableClient/DurableClient.csproj | 94 -- Samples/DurableClient/Form1.Designer.cs | 112 -- Samples/DurableClient/Form1.cs | 44 - Samples/DurableClient/Form1.resx | 120 -- Samples/DurableClient/Program.cs | 149 --- .../DurableClient/Properties/AssemblyInfo.cs | 36 - .../Properties/Resources.Designer.cs | 71 -- .../DurableClient/Properties/Resources.resx | 117 -- .../Properties/Settings.Designer.cs | 30 - .../Properties/Settings.settings | 7 - Samples/DurableServer/DurableServer.csproj | 94 -- Samples/DurableServer/Form1.Designer.cs | 89 -- Samples/DurableServer/Form1.cs | 36 - Samples/DurableServer/Form1.resx | 120 -- Samples/DurableServer/Program.cs | 166 --- .../DurableServer/Properties/AssemblyInfo.cs | 36 - .../Properties/Resources.Designer.cs | 71 -- .../DurableServer/Properties/Resources.resx | 117 -- .../Properties/Settings.Designer.cs | 30 - .../Properties/Settings.settings | 7 - Samples/ImageClient/Form1.Designer.cs | 87 -- Samples/ImageClient/Form1.cs | 37 - Samples/ImageClient/Form1.resx | 120 -- Samples/ImageClient/ImageClient.csproj | 110 -- Samples/ImageClient/ImageGetter.Designer.cs | 72 -- Samples/ImageClient/ImageGetter.cs | 158 --- Samples/ImageClient/ImageGetter.resx | 120 -- Samples/ImageClient/Program.cs | 46 - .../ImageClient/Properties/AssemblyInfo.cs | 36 - .../Properties/Resources.Designer.cs | 71 -- Samples/ImageClient/Properties/Resources.resx | 117 -- .../Properties/Settings.Designer.cs | 30 - .../ImageClient/Properties/Settings.settings | 7 - Samples/ImageServer/Form1.Designer.cs | 89 -- Samples/ImageServer/Form1.cs | 46 - Samples/ImageServer/Form1.resx | 120 -- Samples/ImageServer/ImageServer.csproj | 93 -- Samples/ImageServer/Program.cs | 172 --- .../ImageServer/Properties/AssemblyInfo.cs | 36 - .../Properties/Resources.Designer.cs | 71 -- Samples/ImageServer/Properties/Resources.resx | 117 -- .../Properties/Settings.Designer.cs | 30 - .../ImageServer/Properties/Settings.settings | 7 - Samples/ManyClients/Client.Designer.cs | 61 - Samples/ManyClients/Client.cs | 82 -- Samples/ManyClients/Client.resx | 120 -- Samples/ManyClients/Form1.Designer.cs | 75 -- Samples/ManyClients/Form1.cs | 24 - Samples/ManyClients/Form1.resx | 120 -- Samples/ManyClients/ManyClients.csproj | 110 -- Samples/ManyClients/Program.cs | 45 - .../ManyClients/Properties/AssemblyInfo.cs | 36 - .../Properties/Resources.Designer.cs | 71 -- Samples/ManyClients/Properties/Resources.resx | 117 -- .../Properties/Settings.Designer.cs | 30 - .../ManyClients/Properties/Settings.settings | 7 - Samples/ManyServer/Form1.Designer.cs | 64 -- Samples/ManyServer/Form1.cs | 19 - Samples/ManyServer/Form1.resx | 120 -- Samples/ManyServer/ManyServer.csproj | 99 -- Samples/ManyServer/Program.cs | 81 -- Samples/ManyServer/Properties/AssemblyInfo.cs | 36 - .../Properties/Resources.Designer.cs | 71 -- Samples/ManyServer/Properties/Resources.resx | 117 -- .../Properties/Settings.Designer.cs | 30 - .../ManyServer/Properties/Settings.settings | 7 - .../MSClient/MSClient.csproj | 6 +- .../MSCommon/MSCommon.csproj | 4 + .../MSServer/MSServer.csproj | 4 + .../MasterServer/MasterServer.csproj | 6 +- .../MasterServerSample/MasterServerSample.sln | 32 +- Samples/SamplesCommon/NativeMethods.cs | 58 - .../NetPeerSettingsWindow.Designer.cs | 362 ------ .../SamplesCommon/NetPeerSettingsWindow.cs | 158 --- .../SamplesCommon/NetPeerSettingsWindow.resx | 120 -- .../SamplesCommon/Properties/AssemblyInfo.cs | 36 - Samples/SamplesCommon/SamplesCommon.csproj | 72 -- UnitTests/BitVectorTests.cs | 2 + UnitTests/EncryptionTests.cs | 84 -- UnitTests/ReadWriteTests.cs | 21 +- UnitTests/UnitTests.csproj | 15 +- 167 files changed, 4065 insertions(+), 9640 deletions(-) create mode 100644 Lidgren.Network/NetDeliveryMethod.cs create mode 100644 Lidgren.Network/NetFragmentationHelper.cs delete mode 100644 Lidgren.Network/NetIncomingMessage.Stream.cs delete mode 100644 Lidgren.Network/NetOutgoingMessage.Stream.cs create mode 100644 Lidgren.Network/NetPeer.Fragmentation.cs create mode 100644 Lidgren.Network/NetPeer.MessagePools.cs create mode 100644 Lidgren.Network/NetPeer.Send.cs create mode 100644 Lidgren.Network/NetReceiverChannelBase.cs create mode 100644 Lidgren.Network/NetReliableOrderedReceiver.cs create mode 100644 Lidgren.Network/NetReliableSenderChannel.cs create mode 100644 Lidgren.Network/NetReliableSequencedReceiver.cs create mode 100644 Lidgren.Network/NetReliableUnorderedReceiver.cs create mode 100644 Lidgren.Network/NetSendResult.cs create mode 100644 Lidgren.Network/NetSenderChannelBase.cs delete mode 100644 Lidgren.Network/NetSending.cs create mode 100644 Lidgren.Network/NetStoredReliableMessage.cs create mode 100644 Lidgren.Network/NetTuple.cs create mode 100644 Lidgren.Network/NetUnreliableSenderChannel.cs create mode 100644 Lidgren.Network/NetUnreliableSequencedReceiver.cs create mode 100644 Lidgren.Network/NetUnreliableUnorderedReceiver.cs create mode 100644 Lidgren.Network/SenderChannelBase.cs delete mode 100644 Samples/BarebonesClient/BarebonesClient.csproj delete mode 100644 Samples/BarebonesClient/Program.cs delete mode 100644 Samples/BarebonesClient/Properties/AssemblyInfo.cs delete mode 100644 Samples/BarebonesServer/BarebonesServer.csproj delete mode 100644 Samples/BarebonesServer/Program.cs delete mode 100644 Samples/BarebonesServer/Properties/AssemblyInfo.cs create mode 100644 Samples/Chat/Chat.sln rename Samples/{ => Chat}/ChatClient/ChatClient.csproj (86%) rename Samples/{ => Chat}/ChatClient/Form1.Designer.cs (52%) create mode 100644 Samples/Chat/ChatClient/Form1.cs rename Samples/{ => Chat}/ChatClient/Form1.resx (100%) create mode 100644 Samples/Chat/ChatClient/Program.cs rename Samples/{ => Chat}/ChatClient/Properties/AssemblyInfo.cs (93%) rename Samples/{ => Chat}/ChatClient/Properties/Resources.Designer.cs (95%) rename Samples/{ => Chat}/ChatClient/Properties/Resources.resx (100%) rename Samples/{ => Chat}/ChatClient/Properties/Settings.Designer.cs (93%) rename Samples/{ => Chat}/ChatClient/Properties/Settings.settings (100%) rename Samples/{ => Chat}/ChatServer/ChatServer.csproj (86%) create mode 100644 Samples/Chat/ChatServer/Form1.Designer.cs create mode 100644 Samples/Chat/ChatServer/Form1.cs rename Samples/{ => Chat}/ChatServer/Form1.resx (100%) create mode 100644 Samples/Chat/ChatServer/Program.cs rename Samples/{ => Chat}/ChatServer/Properties/AssemblyInfo.cs (93%) rename Samples/{ => Chat}/ChatServer/Properties/Resources.Designer.cs (95%) rename Samples/{ => Chat}/ChatServer/Properties/Resources.resx (100%) rename Samples/{ => Chat}/ChatServer/Properties/Settings.Designer.cs (93%) rename Samples/{ => Chat}/ChatServer/Properties/Settings.settings (100%) delete mode 100644 Samples/ChatClient/Form1.cs delete mode 100644 Samples/ChatClient/Program.cs delete mode 100644 Samples/ChatServer/Form1.Designer.cs delete mode 100644 Samples/ChatServer/Form1.cs delete mode 100644 Samples/ChatServer/Program.cs delete mode 100644 Samples/DurableClient/DurableClient.csproj delete mode 100644 Samples/DurableClient/Form1.Designer.cs delete mode 100644 Samples/DurableClient/Form1.cs delete mode 100644 Samples/DurableClient/Form1.resx delete mode 100644 Samples/DurableClient/Program.cs delete mode 100644 Samples/DurableClient/Properties/AssemblyInfo.cs delete mode 100644 Samples/DurableClient/Properties/Resources.Designer.cs delete mode 100644 Samples/DurableClient/Properties/Resources.resx delete mode 100644 Samples/DurableClient/Properties/Settings.Designer.cs delete mode 100644 Samples/DurableClient/Properties/Settings.settings delete mode 100644 Samples/DurableServer/DurableServer.csproj delete mode 100644 Samples/DurableServer/Form1.Designer.cs delete mode 100644 Samples/DurableServer/Form1.cs delete mode 100644 Samples/DurableServer/Form1.resx delete mode 100644 Samples/DurableServer/Program.cs delete mode 100644 Samples/DurableServer/Properties/AssemblyInfo.cs delete mode 100644 Samples/DurableServer/Properties/Resources.Designer.cs delete mode 100644 Samples/DurableServer/Properties/Resources.resx delete mode 100644 Samples/DurableServer/Properties/Settings.Designer.cs delete mode 100644 Samples/DurableServer/Properties/Settings.settings delete mode 100644 Samples/ImageClient/Form1.Designer.cs delete mode 100644 Samples/ImageClient/Form1.cs delete mode 100644 Samples/ImageClient/Form1.resx delete mode 100644 Samples/ImageClient/ImageClient.csproj delete mode 100644 Samples/ImageClient/ImageGetter.Designer.cs delete mode 100644 Samples/ImageClient/ImageGetter.cs delete mode 100644 Samples/ImageClient/ImageGetter.resx delete mode 100644 Samples/ImageClient/Program.cs delete mode 100644 Samples/ImageClient/Properties/AssemblyInfo.cs delete mode 100644 Samples/ImageClient/Properties/Resources.Designer.cs delete mode 100644 Samples/ImageClient/Properties/Resources.resx delete mode 100644 Samples/ImageClient/Properties/Settings.Designer.cs delete mode 100644 Samples/ImageClient/Properties/Settings.settings delete mode 100644 Samples/ImageServer/Form1.Designer.cs delete mode 100644 Samples/ImageServer/Form1.cs delete mode 100644 Samples/ImageServer/Form1.resx delete mode 100644 Samples/ImageServer/ImageServer.csproj delete mode 100644 Samples/ImageServer/Program.cs delete mode 100644 Samples/ImageServer/Properties/AssemblyInfo.cs delete mode 100644 Samples/ImageServer/Properties/Resources.Designer.cs delete mode 100644 Samples/ImageServer/Properties/Resources.resx delete mode 100644 Samples/ImageServer/Properties/Settings.Designer.cs delete mode 100644 Samples/ImageServer/Properties/Settings.settings delete mode 100644 Samples/ManyClients/Client.Designer.cs delete mode 100644 Samples/ManyClients/Client.cs delete mode 100644 Samples/ManyClients/Client.resx delete mode 100644 Samples/ManyClients/Form1.Designer.cs delete mode 100644 Samples/ManyClients/Form1.cs delete mode 100644 Samples/ManyClients/Form1.resx delete mode 100644 Samples/ManyClients/ManyClients.csproj delete mode 100644 Samples/ManyClients/Program.cs delete mode 100644 Samples/ManyClients/Properties/AssemblyInfo.cs delete mode 100644 Samples/ManyClients/Properties/Resources.Designer.cs delete mode 100644 Samples/ManyClients/Properties/Resources.resx delete mode 100644 Samples/ManyClients/Properties/Settings.Designer.cs delete mode 100644 Samples/ManyClients/Properties/Settings.settings delete mode 100644 Samples/ManyServer/Form1.Designer.cs delete mode 100644 Samples/ManyServer/Form1.cs delete mode 100644 Samples/ManyServer/Form1.resx delete mode 100644 Samples/ManyServer/ManyServer.csproj delete mode 100644 Samples/ManyServer/Program.cs delete mode 100644 Samples/ManyServer/Properties/AssemblyInfo.cs delete mode 100644 Samples/ManyServer/Properties/Resources.Designer.cs delete mode 100644 Samples/ManyServer/Properties/Resources.resx delete mode 100644 Samples/ManyServer/Properties/Settings.Designer.cs delete mode 100644 Samples/ManyServer/Properties/Settings.settings delete mode 100644 Samples/SamplesCommon/NativeMethods.cs delete mode 100644 Samples/SamplesCommon/NetPeerSettingsWindow.Designer.cs delete mode 100644 Samples/SamplesCommon/NetPeerSettingsWindow.cs delete mode 100644 Samples/SamplesCommon/NetPeerSettingsWindow.resx delete mode 100644 Samples/SamplesCommon/Properties/AssemblyInfo.cs delete mode 100644 Samples/SamplesCommon/SamplesCommon.csproj diff --git a/Lidgren.Network/NetBitVector.cs b/Lidgren.Network/NetBitVector.cs index a14c8ca..52bbfb5 100644 --- a/Lidgren.Network/NetBitVector.cs +++ b/Lidgren.Network/NetBitVector.cs @@ -22,11 +22,18 @@ using System.Text; namespace Lidgren.Network { + /// + /// Fixed size vector of booleans + /// public sealed class NetBitVector { private readonly int m_capacity; private readonly int[] m_data; + private int m_numBitsSet; + /// + /// Gets the number of bits/booleans stored in this vector + /// public int Capacity { get { return m_capacity; } } public NetBitVector(int bitsCapacity) @@ -35,12 +42,21 @@ namespace Lidgren.Network m_data = new int[(bitsCapacity + 31) / 32]; } + /// + /// Returns true if all bits/booleans are set to zero/false + /// public bool IsEmpty() { - foreach (int v in m_data) - if (v != 0) - return false; - return true; + return (m_numBitsSet == 0); + } + + /// + /// Returns the number of bits/booleans set to one/true + /// + /// + public int Count() + { + return m_numBitsSet; } /// @@ -62,6 +78,8 @@ namespace Lidgren.Network cur |= firstBit << lastIndex; m_data[lenMinusOne] = cur; + + throw new NetException("TODO: update m_numBitsSet"); } public int GetFirstSetIndex() @@ -82,20 +100,41 @@ namespace Lidgren.Network return (idx * 32) + a; } + /// + /// Gets the bit/bool at the specified index + /// public bool Get(int bitIndex) { + NetException.Assert(bitIndex >= 0 && bitIndex < m_capacity); + return (m_data[bitIndex / 32] & (1 << (bitIndex % 32))) != 0; } + /// + /// Sets or clears the bit/bool at the specified index + /// public void Set(int bitIndex, bool value) { + NetException.Assert(bitIndex >= 0 && bitIndex < m_capacity); + int idx = bitIndex / 32; if (value) + { + if ((m_data[idx] & (1 << (bitIndex % 32))) == 0) + m_numBitsSet++; m_data[idx] |= (1 << (bitIndex % 32)); + } else + { + if ((m_data[idx] & (1 << (bitIndex % 32))) != 0) + m_numBitsSet--; m_data[idx] &= (~(1 << (bitIndex % 32))); + } } + /// + /// Gets the bit/bool at the specified index + /// [System.Runtime.CompilerServices.IndexerName("Bit")] public bool this[int index] { @@ -103,9 +142,13 @@ namespace Lidgren.Network set { Set(index, value); } } + /// + /// Sets all bits/booleans to zero/false + /// public void Clear() { Array.Clear(m_data, 0, m_data.Length); + m_numBitsSet = 0; } public override string ToString() diff --git a/Lidgren.Network/NetClient.cs b/Lidgren.Network/NetClient.cs index 18c4280..b40e60e 100644 --- a/Lidgren.Network/NetClient.cs +++ b/Lidgren.Network/NetClient.cs @@ -21,6 +21,9 @@ using System.Net; namespace Lidgren.Network { + /// + /// Specialized version of NetPeer used for a "client" connection. It does not accept any incoming connections and maintains a ServerConnection property + /// public class NetClient : NetPeer { /// @@ -53,9 +56,9 @@ namespace Lidgren.Network config.AcceptIncomingConnections = false; } - public override NetConnection Connect(IPEndPoint remoteEndpoint, NetOutgoingMessage approvalMessage) + public override NetConnection Connect(IPEndPoint remoteEndpoint, NetOutgoingMessage hailMessage) { - lock(m_connections) + lock (m_connections) { if (m_connections.Count > 0) { @@ -63,7 +66,7 @@ namespace Lidgren.Network return null; } } - return base.Connect(remoteEndpoint, approvalMessage); + return base.Connect(remoteEndpoint, hailMessage); } /// @@ -84,13 +87,13 @@ namespace Lidgren.Network /// /// Sends message to server /// - public bool SendMessage(NetOutgoingMessage msg, NetDeliveryMethod method) + public NetSendResult SendMessage(NetOutgoingMessage msg, NetDeliveryMethod method) { NetConnection serverConnection = ServerConnection; if (serverConnection == null) { - //LogError("Cannot send message, no server connection!"); - return false; + LogWarning("Cannot send message, no server connection!"); + return NetSendResult.Failed; } return serverConnection.SendMessage(msg, method, 0); @@ -99,13 +102,13 @@ namespace Lidgren.Network /// /// Sends message to server /// - public bool SendMessage(NetOutgoingMessage msg, NetDeliveryMethod method, int sequenceChannel) + public NetSendResult SendMessage(NetOutgoingMessage msg, NetDeliveryMethod method, int sequenceChannel) { NetConnection serverConnection = ServerConnection; if (serverConnection == null) { - //LogError("Cannot send message, no server connection!"); - return false; + LogWarning("Cannot send message, no server connection!"); + return NetSendResult.Failed; } return serverConnection.SendMessage(msg, method, sequenceChannel); diff --git a/Lidgren.Network/NetConnection.Handshake.cs b/Lidgren.Network/NetConnection.Handshake.cs index 3fdac82..57a9c77 100644 --- a/Lidgren.Network/NetConnection.Handshake.cs +++ b/Lidgren.Network/NetConnection.Handshake.cs @@ -1,263 +1,361 @@ -/* Copyright (c) 2010 Michael Lidgren - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software -and associated documentation files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom -the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ -using System; +using System; using System.Collections.Generic; +using System.Linq; +using System.Text; namespace Lidgren.Network { public partial class NetConnection { internal bool m_connectRequested; - internal string m_disconnectByeMessage; + internal bool m_disconnectRequested; internal bool m_connectionInitiator; - internal double m_connectInitationTime; // regardless of initiator - internal NetOutgoingMessage m_approvalMessage; + internal string m_disconnectMessage; + internal NetIncomingMessage m_remoteHailMessage; - internal void SetStatus(NetConnectionStatus status, string reason) + /// + /// The message that the remote part specified via Connect() or Approve() - can be null. + /// + public NetIncomingMessage RemoteHailMessage { get { return m_remoteHailMessage; } } + + internal void UnconnectedHeartbeat(float now) { - if (status == m_status) + m_peer.VerifyNetworkThread(); + + if (m_disconnectRequested) + ExecuteDisconnect(m_disconnectMessage, true); + + if (m_connectRequested) + { + switch (m_status) + { + case NetConnectionStatus.Connected: + case NetConnectionStatus.RespondedConnect: + // reconnect + ExecuteDisconnect("Reconnecting", true); + break; + case NetConnectionStatus.InitiatedConnect: + // send another connect attempt + SendConnect(); + break; + case NetConnectionStatus.Disconnected: + throw new NetException("This connection is Disconnected; spent. A new one should have been created"); + + case NetConnectionStatus.Disconnecting: + // let disconnect finish first + return; + case NetConnectionStatus.None: + default: + SendConnect(); + break; + } return; - m_status = status; - if (reason == null) - reason = string.Empty; + } - if (m_peerConfiguration.IsMessageTypeEnabled(NetIncomingMessageType.StatusChanged)) - { - NetIncomingMessage info = m_owner.CreateIncomingMessage(NetIncomingMessageType.StatusChanged, 4 + reason.Length + (reason.Length > 126 ? 2 : 1)); - info.m_senderConnection = this; - info.m_senderEndpoint = m_remoteEndpoint; - info.Write((byte)m_status); - info.Write(reason); - m_owner.ReleaseMessage(info); - } - else - { - // app dont want those messages, update visible status immediately - m_visibleStatus = m_status; - } + // TODO: handle dangling connections } - private void SendConnect() + internal void ExecuteDisconnect(string reason, bool sendByeMessage) { - m_owner.VerifyNetworkThread(); + m_peer.VerifyNetworkThread(); - switch (m_status) + // m_peer.LogDebug("Executing disconnect"); + + // clear send queues + for (int i = 0; i < m_sendChannels.Length; i++) { - case NetConnectionStatus.Connected: - // reconnect - m_disconnectByeMessage = "Reconnecting"; - ExecuteDisconnect(true); - FinishDisconnect(); - break; - case NetConnectionStatus.Connecting: - case NetConnectionStatus.None: - break; - case NetConnectionStatus.Disconnected: - throw new NetException("This connection is Disconnected; spent. A new one should have been created"); - - case NetConnectionStatus.Disconnecting: - // let disconnect finish first - return; + NetSenderChannelBase channel = m_sendChannels[i]; + if (channel != null) + channel.Reset(); } + if (sendByeMessage) + SendDisconnect(reason, true); + + SetStatus(NetConnectionStatus.Disconnected, reason); + m_disconnectRequested = false; m_connectRequested = false; - - // start handshake - - int len = 2 + m_peerConfiguration.AppIdentifier.Length + 8 + 4 + (m_approvalMessage == null ? 0 : m_approvalMessage.LengthBytes); - NetOutgoingMessage om = m_owner.CreateMessage(len); - om.m_libType = NetMessageLibraryType.Connect; - om.Write(m_peerConfiguration.AppIdentifier); - om.Write(m_owner.m_uniqueIdentifier); - - if (m_approvalMessage == null) - { - om.WriteVariableUInt32(0); - } - else - { - om.WriteVariableUInt32((uint)m_approvalMessage.LengthBits); - om.Write(m_approvalMessage); - } - m_owner.LogVerbose("Sending Connect"); - - m_owner.SendLibraryImmediately(om, m_remoteEndpoint); - - m_connectInitationTime = NetTime.Now; - SetStatus(NetConnectionStatus.Connecting, "Connecting"); - - return; } - internal void SendConnectResponse() + internal void SendConnect() { - double now = NetTime.Now; + NetOutgoingMessage om = m_peer.CreateMessage(m_peerConfiguration.AppIdentifier.Length + 1 + 4); + om.m_messageType = NetMessageType.Connect; + om.Write(m_peerConfiguration.AppIdentifier); + om.Write(m_peer.m_uniqueIdentifier); - NetOutgoingMessage reply = m_owner.CreateMessage(4); - reply.m_libType = NetMessageLibraryType.ConnectResponse; - reply.Write((float)now); + WriteLocalHail(om); + + m_peer.SendLibrary(om, m_remoteEndpoint); - m_owner.LogVerbose("Sending LibraryConnectResponse"); - m_owner.SendLibraryImmediately(reply, m_remoteEndpoint); + SetStatus(NetConnectionStatus.InitiatedConnect, "Locally requested connect"); + m_connectRequested = false; + } + + internal void SendConnectResponse(bool onLibraryThread) + { + NetOutgoingMessage om = m_peer.CreateMessage(m_peerConfiguration.AppIdentifier.Length + 1 + 4); + om.m_messageType = NetMessageType.ConnectResponse; + om.Write(m_peerConfiguration.AppIdentifier); + om.Write(m_peer.m_uniqueIdentifier); + + WriteLocalHail(om); + + if (onLibraryThread) + m_peer.SendLibrary(om, m_remoteEndpoint); + else + m_peer.m_unsentUnconnectedMessages.Enqueue(new NetTuple(m_remoteEndpoint, om)); + + SetStatus(NetConnectionStatus.RespondedConnect, "Remotely requested connect"); + } + + internal void SendDisconnect(string reason, bool onLibraryThread) + { + NetOutgoingMessage om = m_peer.CreateMessage(reason); + om.m_messageType = NetMessageType.Disconnect; + if (onLibraryThread) + m_peer.SendLibrary(om, m_remoteEndpoint); + else + m_peer.m_unsentUnconnectedMessages.Enqueue(new NetTuple(m_remoteEndpoint, om)); + } + + private void WriteLocalHail(NetOutgoingMessage om) + { + if (m_localHailMessage != null) + { + byte[] hi = m_localHailMessage.PeekDataBuffer(); + if (hi != null && hi.Length >= m_localHailMessage.LengthBytes) + { + if (om.LengthBytes + m_localHailMessage.LengthBytes > m_peerConfiguration.m_maximumTransmissionUnit - 10) + throw new NetException("Hail message too large; can maximally be " + (m_peerConfiguration.m_maximumTransmissionUnit - 10 - om.LengthBytes)); + om.Write(m_localHailMessage.PeekDataBuffer(), 0, m_localHailMessage.LengthBytes); + } + } } internal void SendConnectionEstablished() { - double now = NetTime.Now; + NetOutgoingMessage om = m_peer.CreateMessage(0); + om.m_messageType = NetMessageType.ConnectionEstablished; + m_peer.SendLibrary(om, m_remoteEndpoint); - NetOutgoingMessage ce = m_owner.CreateMessage(4); - ce.m_libType = NetMessageLibraryType.ConnectionEstablished; - ce.Write((float)now); - - m_owner.LogVerbose("Sending LibraryConnectionEstablished"); - m_owner.SendLibraryImmediately(ce, m_remoteEndpoint); + m_sentPingTime = (float)NetTime.Now - (m_peerConfiguration.PingInterval / 2.0f); // delay ping for a little while + if (m_status != NetConnectionStatus.Connected) + SetStatus(NetConnectionStatus.Connected, "Connected to " + NetUtility.ToHexString(m_remoteUniqueIdentifier)); } - internal void ExecuteDisconnect(bool sendByeMessage) + /// + /// Approves this connection; sending a connection response to the remote host + /// + public void Approve() { - m_owner.VerifyNetworkThread(); + m_localHailMessage = null; + SendConnectResponse(false); + } - if (m_status == NetConnectionStatus.Disconnected || m_status == NetConnectionStatus.None) - return; + /// + /// Approves this connection; sending a connection response to the remote host + /// + /// The local hail message that will be set as RemoteHailMessage on the remote host + public void Approve(NetOutgoingMessage localHail) + { + m_localHailMessage = localHail; + SendConnectResponse(false); + } - if (sendByeMessage) + /// + /// Denies this connection; disconnecting it + /// + public void Deny() + { + Deny(""); + } + + /// + /// Denies this connection; disconnecting it + /// + /// The stated reason for the disconnect, readable as a string in the StatusChanged message on the remote host + public void Deny(string reason) + { + // send disconnect; remove from handshakes + SendDisconnect(reason, false); + + // remove from handshakes + 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) + { + m_peer.VerifyNetworkThread(); + + byte[] hail; + switch (tp) { - NetOutgoingMessage om = m_owner.CreateLibraryMessage(NetMessageLibraryType.Disconnect, m_disconnectByeMessage); - SendLibrary(om); - } - - m_owner.LogVerbose("Executing Disconnect(" + m_disconnectByeMessage + ")"); - - return; - } - - internal void FinishDisconnect() - { - m_owner.VerifyNetworkThread(); - - if (m_status == NetConnectionStatus.Disconnected || m_status == NetConnectionStatus.None) - return; - - m_owner.LogVerbose("Finishing Disconnect(" + m_disconnectByeMessage + ")"); - - if (m_unsentMessages.Count > 0) - m_owner.LogDebug(m_unsentMessages.Count + " unsent messages were not sent before disconnected"); - - // release some held memory - m_unackedSends.Clear(); - m_acknowledgesToSend.Clear(); - foreach(var wma in m_withheldMessages) - if (wma != null) - wma.Clear(); - m_fragmentGroups.Clear(); - - SetStatus(NetConnectionStatus.Disconnected, m_disconnectByeMessage); - m_disconnectByeMessage = null; - m_connectionInitiator = false; - } - - private void HandleIncomingHandshake(NetMessageLibraryType libType, int ptr, int payloadBitsLength) - { - m_owner.VerifyNetworkThread(); - - switch (libType) - { - case NetMessageLibraryType.Connect: - - m_owner.LogDebug("Received Connect"); - - if (m_status == NetConnectionStatus.Connecting) + case NetMessageType.Connect: + if (m_status == NetConnectionStatus.None) { - // our connectresponse must have been lost, send another one - SendConnectResponse(); + // Whee! Server full has already been checked + bool ok = ValidateHandshakeData(ptr, payloadLength, out hail); + if (ok) + { + if (hail != null) + { + m_remoteHailMessage = m_peer.CreateIncomingMessage(NetIncomingMessageType.Data, hail); + m_remoteHailMessage.LengthBits = (hail.Length * 8); + } + else + { + m_remoteHailMessage = null; + } + + if (m_peerConfiguration.IsMessageTypeEnabled(NetIncomingMessageType.ConnectionApproval)) + { + // ok, let's not add connection just yet + NetIncomingMessage appMsg = m_peer.CreateIncomingMessage(NetIncomingMessageType.ConnectionApproval, m_remoteHailMessage.LengthBytes); + appMsg.m_senderConnection = this; + appMsg.m_senderEndpoint = this.m_remoteEndpoint; + appMsg.Write(m_remoteHailMessage.m_data, 0, m_remoteHailMessage.LengthBytes); + m_peer.ReleaseMessage(appMsg); + return; + } + + SendConnectResponse(true); + } return; } - if (m_connectionInitiator) - m_owner.LogError("Received Connect; altho we're connect initiator! Status is " + m_status); - else - m_owner.LogError("NetConnection.HandleIncomingHandshake() passed LibraryConnect but status is " + m_status + "!? now is " + NetTime.Now + " LastHeardFrom is " + m_lastHeardFrom); + if (m_status == NetConnectionStatus.RespondedConnect) + { + // our ConnectResponse must have been lost + SendConnectResponse(true); + return; + } + m_peer.LogDebug("Unhandled handshake: " + tp + ", status is " + m_status + " length: " + payloadLength); break; - case NetMessageLibraryType.ConnectResponse: - if (!m_connectionInitiator) + case NetMessageType.ConnectResponse: + switch (m_status) { - m_owner.LogError("NetConnection.HandleIncomingHandshake() passed LibraryConnectResponse, but we're not initiator!"); - // weird, just drop it - return; + case NetConnectionStatus.InitiatedConnect: + // awesome + bool ok = ValidateHandshakeData(ptr, payloadLength, out hail); + if (ok) + { + if (hail != null) + { + m_remoteHailMessage = m_peer.CreateIncomingMessage(NetIncomingMessageType.Data, hail); + m_remoteHailMessage.LengthBits = (hail.Length * 8); + } + else + { + m_remoteHailMessage = null; + } + + m_peer.AcceptConnection(this); + SendConnectionEstablished(); + return; + } + break; + case NetConnectionStatus.RespondedConnect: + // hello, wtf? + break; + case NetConnectionStatus.Disconnecting: + case NetConnectionStatus.Disconnected: + case NetConnectionStatus.None: + // wtf? anyway, bye! + break; + case NetConnectionStatus.Connected: + // my ConnectionEstablished must have been lost, send another one + SendConnectionEstablished(); + return; } - - m_owner.LogDebug("Received ConnectResponse"); - - if (m_status == NetConnectionStatus.Connecting) - { - m_owner.m_statistics.m_bytesAllocated += NetUtility.BytesToHoldBits(payloadBitsLength); - - float remoteNetTime = BitConverter.ToSingle(m_owner.m_receiveBuffer, ptr); - ptr += 4; - - // excellent, handshake making progress; send connectionestablished - SetStatus(NetConnectionStatus.Connected, "Connected"); - - SendConnectionEstablished(); - - // setup initial ping estimation - InitializeLatency((float)(NetTime.Now - m_connectInitationTime), remoteNetTime); - return; - } - - if (m_status == NetConnectionStatus.Connected) - { - // received (another) connectresponse; our connectionestablished must have been lost, send another one - SendConnectionEstablished(); - return; - } - - m_owner.LogWarning("NetConnection.HandleIncomingHandshake() passed " + libType + ", but status is " + m_status); break; - case NetMessageLibraryType.ConnectionEstablished: - - m_owner.LogDebug("Received ConnectionEstablished"); - - if (!m_connectionInitiator && m_status == NetConnectionStatus.Connecting) + case NetMessageType.ConnectionEstablished: + switch (m_status) { - float remoteNetTime = BitConverter.ToSingle(m_owner.m_receiveBuffer, ptr); - - // handshake done - InitializeLatency((float)(NetTime.Now - m_connectInitationTime), remoteNetTime); - - SetStatus(NetConnectionStatus.Connected, "Connected"); - return; + case NetConnectionStatus.Connected: + // ok... + break; + case NetConnectionStatus.Disconnected: + case NetConnectionStatus.Disconnecting: + case NetConnectionStatus.None: + // too bad, almost made it + break; + case NetConnectionStatus.InitiatedConnect: + // weird, should have been ConnectResponse... + break; + case NetConnectionStatus.RespondedConnect: + // awesome + m_peer.AcceptConnection(this); + m_sentPingTime = (float)NetTime.Now - (m_peerConfiguration.PingInterval / 2.0f); // delay ping for a little while + SetStatus(NetConnectionStatus.Connected, "Connected to " + NetUtility.ToHexString(m_remoteUniqueIdentifier)); + return; } - - m_owner.LogWarning("NetConnection.HandleIncomingHandshake() passed " + libType + ", but initiator is " + m_connectionInitiator + " and status is " + m_status); break; - case NetMessageLibraryType.Disconnect: - // extract bye message - NetIncomingMessage im = m_owner.CreateIncomingMessage(NetIncomingMessageType.Data, m_owner.m_receiveBuffer, ptr, NetUtility.BytesToHoldBits(payloadBitsLength)); - im.m_bitLength = payloadBitsLength; - m_disconnectByeMessage = im.ReadString(); - FinishDisconnect(); + case NetMessageType.Disconnect: + // ouch + string reason = "Ouch"; + try + { + NetIncomingMessage inc = m_peer.SetupReadHelperMessage(ptr, payloadLength); + reason = inc.ReadString(); + } + catch + { + } + SetStatus(NetConnectionStatus.Disconnected, reason); break; default: - // huh? - m_owner.LogWarning("Unhandled library type in " + this + ": " + libType); + m_peer.LogDebug("Unhandled handshake: " + tp + " length: " + payloadLength); break; } } + + private bool ValidateHandshakeData(int ptr, int payloadLength, out byte[] hail) + { + hail = null; + + // create temporary incoming message + NetIncomingMessage msg = m_peer.SetupReadHelperMessage(ptr, payloadLength); + try + { + string remoteAppIdentifier = msg.ReadString(); + long remoteUniqueIdentifier = msg.ReadInt64(); + + int remainingBytes = payloadLength - (msg.PositionInBytes - ptr); + if (remainingBytes > 0) + hail = msg.ReadBytes(remainingBytes); + + if (remoteAppIdentifier != m_peer.m_configuration.AppIdentifier) + { + // wrong app identifier + ExecuteDisconnect("Wrong application identifier!", true); + return false; + } + + m_remoteUniqueIdentifier = remoteUniqueIdentifier; + } + catch(Exception ex) + { + // whatever; we failed + ExecuteDisconnect("Handshake data validation failed", true); + m_peer.LogWarning("ReadRemoteHandshakeData failed: " + ex.Message); + return false; + } + return true; + } + + public void Disconnect(string byeMessage) + { + // user or library thread + if (m_status == NetConnectionStatus.None || m_status == NetConnectionStatus.Disconnected) + return; + + m_peer.LogVerbose("Disconnect requested for " + this); + m_disconnectMessage = byeMessage; + + if (m_status != NetConnectionStatus.Disconnected && m_status != NetConnectionStatus.None) + SetStatus(NetConnectionStatus.Disconnecting, byeMessage); + + m_disconnectRequested = true; + } } } diff --git a/Lidgren.Network/NetConnection.Latency.cs b/Lidgren.Network/NetConnection.Latency.cs index 2b459a8..b934952 100644 --- a/Lidgren.Network/NetConnection.Latency.cs +++ b/Lidgren.Network/NetConnection.Latency.cs @@ -1,161 +1,71 @@ -/* Copyright (c) 2010 Michael Lidgren - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software -and associated documentation files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom -the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ -using System; -using System.Collections.Generic; -using System.Text; +using System; namespace Lidgren.Network { public partial class NetConnection { - // - // Connection keepalive and latency calculation - // - internal float m_averageRoundtripTime = 0.05f; - private byte m_lastSentPingNumber; - private double m_lastPingSendTime; - private double m_nextPing; - internal double m_lastSendRespondedTo; - - // remote + diff = local - // diff = local - remote - // local - diff = remote - internal double m_remoteToLocalNetTime = double.MinValue; + private float m_sentPingTime; + private int m_sentPingNumber; + private float m_averageRoundtripTime; + private float m_timeoutDeadline = float.MaxValue; public float AverageRoundtripTime { get { return m_averageRoundtripTime; } } - internal void InitializeLatency(float rtt, float remoteNetTime) + internal void SendPing() { - m_averageRoundtripTime = Math.Max(0.005f, rtt - 0.005f); // TODO: find out why initial ping always overshoots - m_nextPing = NetTime.Now + m_peerConfiguration.m_pingFrequency / 2.0f; + m_peer.VerifyNetworkThread(); - double currentRemoteNetTime = remoteNetTime - (rtt * 0.5); - m_remoteToLocalNetTime = (float)(NetTime.Now - currentRemoteNetTime); + 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.m_messageType = NetMessageType.Ping; - StringBuilder bdr = new StringBuilder(); - bdr.Append("Initialized average roundtrip time to: "); - bdr.Append(NetTime.ToReadable(m_averageRoundtripTime)); - bdr.Append(" remote time diff to "); - bdr.Append(NetTime.ToReadable(m_remoteToLocalNetTime)); - m_owner.LogDebug(bdr.ToString()); + int len = om.Encode(m_peer.m_sendBuffer, 0, 0); + bool connectionReset; + m_peer.SendPacket(len, m_remoteEndpoint, 1, out connectionReset); } - internal void HandleIncomingPing(byte pingNumber) + internal void SendPong(int pingNumber) { - double now = NetTime.Now; + m_peer.VerifyNetworkThread(); - // send pong - NetOutgoingMessage pong = m_owner.CreateMessage(1 + 8); - pong.m_libType = NetMessageLibraryType.Pong; - pong.Write((byte)pingNumber); - pong.Write(now); + NetOutgoingMessage om = m_peer.CreateMessage(1); + om.Write((byte)pingNumber); + om.m_messageType = NetMessageType.Pong; - m_owner.LogDebug("Sending pong for remote ping #" + pingNumber); - - m_owner.SendLibraryImmediately(pong, m_remoteEndpoint); + int len = om.Encode(m_peer.m_sendBuffer, 0, 0); + bool connectionReset; + m_peer.SendPacket(len, m_remoteEndpoint, 1, out connectionReset); } - internal void HandleIncomingPong(double receiveNow, byte pingNumber, double remoteNetTime) + internal void ReceivedPong(float now, int pongNumber) { - // verify it´s the correct ping number - if (pingNumber != m_lastSentPingNumber) + if (pongNumber != m_sentPingNumber) { - m_owner.LogError("Received wrong pong number; got " + pingNumber + " expected " + m_lastSentPingNumber); - - // but still, a pong must have been triggered by a ping... - double diff = receiveNow - m_lastSendRespondedTo; - if (diff > 0) - m_lastSendRespondedTo += (diff / 2); // postpone timing out a bit - + m_peer.LogVerbose("Ping/Pong mismatch; dropped message?"); return; } - - double now = NetTime.Now; // need exact number - m_lastHeardFrom = now; - if (m_lastPingSendTime > m_lastSendRespondedTo) - m_lastSendRespondedTo = m_lastPingSendTime; + m_timeoutDeadline = now + m_peerConfiguration.m_connectionTimeout; - double rtt = now - m_lastPingSendTime; + float rtt = now - m_sentPingTime; + NetException.Assert(rtt >= 0); - // update clock sync - double currentRemoteNetTime = remoteNetTime - (rtt * 0.5); - double foundDiffRemoteToLocal = receiveNow - currentRemoteNetTime; - - if (m_remoteToLocalNetTime == double.MinValue) - m_remoteToLocalNetTime = foundDiffRemoteToLocal; + if (m_averageRoundtripTime < 0) + { + m_averageRoundtripTime = rtt; // initial estimate + m_peer.LogDebug("Initiated average roundtrip time to " + NetTime.ToReadable(m_averageRoundtripTime)); + } else - m_remoteToLocalNetTime = ((m_remoteToLocalNetTime + foundDiffRemoteToLocal) * 0.5); - - m_averageRoundtripTime = (m_averageRoundtripTime * 0.7f) + (float)(rtt * 0.3f); - m_owner.LogVerbose("Found rtt: " + NetTime.ToReadable(rtt) + ", new average: " + NetTime.ToReadable(m_averageRoundtripTime) + " new time diff: " + NetTime.ToReadable(m_remoteToLocalNetTime)); - } - - internal void KeepAliveHeartbeat(double now) - { - // do keepalive and latency pings - if (m_status == NetConnectionStatus.Disconnected || m_status == NetConnectionStatus.None) - return; - - // force ack sending? - if (now > m_nextForceAckTime) { - // send keepalive thru regular channels to give acks something to piggyback on - NetOutgoingMessage pig = m_owner.CreateMessage(1); - pig.m_libType = NetMessageLibraryType.KeepAlive; - SendLibrary(pig); - m_nextForceAckTime = now + m_peerConfiguration.m_maxAckDelayTime; + m_averageRoundtripTime = (m_averageRoundtripTime * 0.7f) + (float)(rtt * 0.3f); + m_peer.LogVerbose("Updated average roundtrip time to " + NetTime.ToReadable(m_averageRoundtripTime)); } - // timeout - if (now > m_lastSendRespondedTo + m_peerConfiguration.m_connectionTimeout) - { - m_owner.LogDebug(this + " timed out; now is " + now + " last responded to is: " + m_lastSendRespondedTo); - Disconnect("Timed out after " + (now - m_lastSendRespondedTo) + " seconds"); - return; - } - - // ping time? - if (now >= m_nextPing) - { - // - // send ping - // - now = NetTime.Now; // need exact number - m_lastSentPingNumber++; - m_lastPingSendTime = now; - - m_owner.LogDebug("Sending ping #" + m_lastSentPingNumber); - - // in case of not heard for a while - if (m_lastSendRespondedTo > 0 && (now > m_lastSendRespondedTo + (m_owner.Configuration.m_pingFrequency * 1.5f))) - m_nextPing = now + (m_owner.Configuration.m_pingFrequency * 0.5f); // double ping rate - else - m_nextPing = now + m_owner.Configuration.m_pingFrequency; - - NetOutgoingMessage ping = m_owner.CreateMessage(1); - ping.m_libType = NetMessageLibraryType.Ping; - ping.Write((byte)m_lastSentPingNumber); - - m_owner.SendLibraryImmediately(ping, m_remoteEndpoint); - } + m_peer.LogVerbose("Timeout deadline pushed to " + m_timeoutDeadline); } } } diff --git a/Lidgren.Network/NetConnection.cs b/Lidgren.Network/NetConnection.cs index 7103f1d..7bd1612 100644 --- a/Lidgren.Network/NetConnection.cs +++ b/Lidgren.Network/NetConnection.cs @@ -1,817 +1,424 @@ -/* Copyright (c) 2010 Michael Lidgren - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software -and associated documentation files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom -the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ -using System; -using System.Collections.Generic; -using System.Diagnostics; +using System; using System.Net; using System.Threading; +using System.Diagnostics; namespace Lidgren.Network { - [DebuggerDisplay("RemoteEndpoint={m_remoteEndpoint} Status={m_status}")] + /// + /// Represents a connection to a remote peer + /// + [DebuggerDisplay("RemoteUniqueIdentifier={RemoteUniqueIdentifier} RemoteEndpoint={RemoteEndpoint}")] public partial class NetConnection { - private static readonly NetFragmentationInfo s_genericFragmentationInfo = new NetFragmentationInfo(); - - internal readonly NetPeer m_owner; - internal readonly IPEndPoint m_remoteEndpoint; - internal double m_lastHeardFrom; - internal readonly NetQueue m_unsentMessages; + internal NetPeer m_peer; + internal NetPeerConfiguration m_peerConfiguration; internal NetConnectionStatus m_status; internal NetConnectionStatus m_visibleStatus; - private double m_lastSentUnsentMessages; - private float m_throttleDebt; - private readonly NetPeerConfiguration m_peerConfiguration; - internal NetConnectionStatistics m_statistics; - private int m_lesserHeartbeats; - private int m_nextFragmentGroupId; + internal IPEndPoint m_remoteEndpoint; + internal NetSenderChannelBase[] m_sendChannels; + internal NetReceiverChannelBase[] m_receiveChannels; + internal NetOutgoingMessage m_localHailMessage; internal long m_remoteUniqueIdentifier; - private readonly Dictionary m_fragmentGroups; - private int m_handshakeAttempts; - - internal PendingConnectionStatus m_pendingStatus = PendingConnectionStatus.NotPending; - internal string m_pendingDenialReason; + internal NetQueue> m_queuedAcks; + private int m_sendBufferWritePtr; + private int m_sendBufferNumMessages; + internal NetConnectionStatistics m_statistics; /// - /// Gets or sets the object containing data about the connection + /// Gets the peer which holds this connection /// - public object Tag { get; set; } + public NetPeer Peer { get { return m_peer; } } /// - /// Statistics for the connection + /// Gets the current status of the connection (synced to the last status message read) + /// + public NetConnectionStatus Status { get { return m_visibleStatus; } } + + /// + /// Gets various statistics for this connection /// public NetConnectionStatistics Statistics { get { return m_statistics; } } - /// - /// The unique identifier of the remote NetPeer for this connection - /// - public long RemoteUniqueIdentifier { get { return m_remoteUniqueIdentifier; } } - - /// - /// The current status of the connection - /// - public NetConnectionStatus Status - { - get { return m_visibleStatus; } - } - /// /// Gets the remote endpoint for the connection /// public IPEndPoint RemoteEndpoint { get { return m_remoteEndpoint; } } /// - /// Gets the owning NetPeer instance + /// Gets the unique identifier of the remote NetPeer for this connection /// - public NetPeer Owner { get { return m_owner; } } + public long RemoteUniqueIdentifier { get { return m_remoteUniqueIdentifier; } } - /// - /// Gets the number of bytes queued for sending to this connection - /// - public int UnsentBytesCount + // gets the time before automatically resending an unacked message + internal float GetResendDelay() { - get - { - int mtu = m_owner.Configuration.MaximumTransmissionUnit - NetConstants.FragmentHeaderSize; - int retval = 0; - - NetSending[] arr = m_unsentMessages.ToArray(); - foreach (NetSending send in arr) - { - if (send.FragmentGroupId == 0) - { - retval += send.Message.LengthBytes; - } - else - { - int thisFragmentLength = (send.FragmentNumber == send.FragmentTotalCount - 1 ? (send.Message.LengthBytes - (mtu * (send.FragmentTotalCount - 1))) : mtu); - retval += thisFragmentLength; - } - } - return retval; - } + float avgRtt = m_averageRoundtripTime; + if (avgRtt <= 0) + avgRtt = 0.1f; // "default" resend is based on 100 ms roundtrip time + return 0.01f + (avgRtt * 2); // 10 ms + double rtt } - internal NetConnection(NetPeer owner, IPEndPoint remoteEndpoint) + internal NetConnection(NetPeer peer, IPEndPoint remoteEndpoint) { - m_owner = owner; - m_peerConfiguration = m_owner.m_configuration; - m_remoteEndpoint = remoteEndpoint; - m_fragmentGroups = new Dictionary(); + m_peer = peer; + m_peerConfiguration = m_peer.Configuration; m_status = NetConnectionStatus.None; m_visibleStatus = NetConnectionStatus.None; - m_unsentMessages = new NetQueue(8); - - double now = NetTime.Now; - m_nextPing = now + 10.0f; - m_nextForceAckTime = double.MaxValue; - m_lastSentUnsentMessages = now; - m_lastSendRespondedTo = now; + m_remoteEndpoint = remoteEndpoint; + m_sendChannels = new NetSenderChannelBase[NetConstants.NumTotalChannels]; + m_receiveChannels = new NetReceiverChannelBase[NetConstants.NumTotalChannels]; + m_queuedAcks = new NetQueue>(4); m_statistics = new NetConnectionStatistics(this); - - //InitializeReliability(); - int num = ((int)NetMessageType.UserReliableOrdered + NetConstants.NetChannelsPerDeliveryMethod) - (int)NetMessageType.UserSequenced; - m_nextSendSequenceNumber = new int[num]; - m_lastReceivedSequenced = new ushort[num]; - for (int i = 0; i < m_lastReceivedSequenced.Length; i++) - m_lastReceivedSequenced[i] = ushort.MaxValue; - m_nextForceAckTime = double.MaxValue; + m_averageRoundtripTime = -1.0f; } - // run on network thread - internal void Heartbeat(double now) + internal void SetStatus(NetConnectionStatus status, string reason) { - m_owner.VerifyNetworkThread(); + // user or library thread - m_lesserHeartbeats++; + if (status == m_status) + return; + m_status = status; + if (reason == null) + reason = string.Empty; - if (m_lesserHeartbeats >= 2) + if (m_status == NetConnectionStatus.Connected) { - // - // Do greater heartbeat every third heartbeat - // - m_lesserHeartbeats = 0; - - // keepalive, timeout and ping stuff - KeepAliveHeartbeat(now); - - if (m_connectRequested) - SendConnect(); - - if (m_status == NetConnectionStatus.Connecting && now - m_connectInitationTime > m_owner.m_configuration.m_handshakeAttemptDelay) - { - if (m_connectionInitiator) - SendConnect(); - else - SendConnectResponse(); - - m_connectInitationTime = now; - - if (++m_handshakeAttempts >= m_owner.m_configuration.m_handshakeMaxAttempts) - { - Disconnect("Failed to complete handshake"); - return; - } - } - - // queue resends - foreach (NetSending send in m_unackedSends) - { - if (now > send.NextResend) - { - m_owner.LogVerbose("Resending " + send); - m_unsentMessages.EnqueueFirst(send); - send.SetNextResend(this); - } - } - - /* - if (!m_storedMessagesNotEmpty.IsEmpty()) - { - int first = m_storedMessagesNotEmpty.GetFirstSetIndex(); - -#if DEBUG - // slow slow verification - for (int i = 0; i < first; i++) - if (m_storedMessages[i] != null && m_storedMessages[i].Count > 0) - throw new NetException("m_storedMessagesNotEmpty mismatch; first is " + first + " but actual first is " + i); - if (m_storedMessages[first] == null || m_storedMessages[first].Count < 1) - throw new NetException("m_storedMessagesNotEmpty failure; first is " + first + ", but that entry is empty!"); -#endif - for (int i = first; i < m_storedMessages.Length; i++) - { - if (m_storedMessagesNotEmpty.Get(i)) - { - Dictionary dict = m_storedMessages[i]; - RestartCheck: - foreach (ushort seqNr in m_storedMessages[i].Keys) - { - NetOutgoingMessage om = dict[seqNr]; - if (now >= om.m_nextResendTime) - { - Resend(now, seqNr, om); - goto RestartCheck; // need to break out here; collection may have been modified - } - } - } -#if DEBUG - else - { - NetException.Assert(m_storedMessages[i] == null || m_storedMessages[i].Count < 1, "m_storedMessagesNotEmpty fail!"); - } -#endif - } - } - */ + m_timeoutDeadline = (float)NetTime.Now + m_peerConfiguration.m_connectionTimeout; + m_peer.LogVerbose("Timeout deadline initialized to " + m_timeoutDeadline); } - // send unsent messages; high priority first - byte[] buffer = m_owner.m_sendBuffer; - int ptr = 0; - - float throttle = m_peerConfiguration.m_throttleBytesPerSecond; - if (throttle > 0) + if (m_peerConfiguration.IsMessageTypeEnabled(NetIncomingMessageType.StatusChanged)) { - double frameLength = now - m_lastSentUnsentMessages; - if (m_throttleDebt > 0) - m_throttleDebt -= (float)(frameLength * throttle); + NetIncomingMessage info = m_peer.CreateIncomingMessage(NetIncomingMessageType.StatusChanged, 4 + reason.Length + (reason.Length > 126 ? 2 : 1)); + info.m_senderConnection = this; + info.m_senderEndpoint = m_remoteEndpoint; + info.Write((byte)m_status); + info.Write(reason); + m_peer.ReleaseMessage(info); } else { - // 0 = unlimited (but still respect throttlethreshold per iteration) - m_throttleDebt = 0; + // app dont want those messages, update visible status immediately + m_visibleStatus = m_status; + } + } + + internal void Heartbeat(float now) + { + m_peer.VerifyNetworkThread(); + + NetException.Assert(m_status != NetConnectionStatus.InitiatedConnect && m_status != NetConnectionStatus.RespondedConnect); + + if (now > m_timeoutDeadline) + { + // + // connection timed out + // + m_peer.LogVerbose("Connection timed out at " + now + " deadline was " + m_timeoutDeadline); + ExecuteDisconnect("Connection timed out", true); } - m_lastSentUnsentMessages = now; + // send ping? + if (m_status == NetConnectionStatus.Connected) + { + if (now > m_sentPingTime + m_peer.m_configuration.m_pingInterval) + SendPing(); + } + bool connectionReset; // TODO: handle connection reset + + // + // Note: at this point m_sendBufferWritePtr and m_sendBufferNumMessages may be non-null; resends may already be queued up + // + + byte[] sendBuffer = m_peer.m_sendBuffer; int mtu = m_peerConfiguration.m_maximumTransmissionUnit; - bool useCoalescing = m_peerConfiguration.m_useMessageCoalescing; - float throttleThreshold = m_peerConfiguration.m_throttlePeakBytes; - if (m_throttleDebt < throttleThreshold) + // + // send ack messages + // + while (m_queuedAcks.Count > 0) { - // - // Send new unsent messages - // - int numIncludedMessages = 0; - while (m_unsentMessages.Count > 0) + int acks = (mtu - (m_sendBufferWritePtr + 5)) / 3; // 3 bytes per actual ack + if (acks > m_queuedAcks.Count) + acks = m_queuedAcks.Count; + + NetException.Assert(acks > 0); + + m_sendBufferNumMessages++; + + // write acks header + sendBuffer[m_sendBufferWritePtr++] = (byte)NetMessageType.Acknowledge; + sendBuffer[m_sendBufferWritePtr++] = 0; // no sequence number + sendBuffer[m_sendBufferWritePtr++] = 0; // no sequence number + int len = (acks * 3) * 8; // bits + sendBuffer[m_sendBufferWritePtr++] = (byte)len; + sendBuffer[m_sendBufferWritePtr++] = (byte)(len >> 8); + + // write acks + for(int i=0;i= throttleThreshold) - break; + NetTuple tuple; + m_queuedAcks.TryDequeue(out tuple); - NetSending send; - if (!m_unsentMessages.TryDequeue(out send)) - continue; + //m_peer.LogVerbose("Sending ack for " + tuple.Item1 + "#" + tuple.Item2); - send.NumSends++; - - NetOutgoingMessage msg = send.Message; - int msgPayloadLength = msg.LengthBytes; - - if (ptr > 0) - { - if (!useCoalescing || ((ptr + NetPeer.kMaxPacketHeaderSize + msgPayloadLength) > mtu)) - { - // send packet and start new packet - bool connectionReset; - m_owner.SendPacket(ptr, m_remoteEndpoint, numIncludedMessages, out connectionReset); - if (connectionReset) - { - // ouch! can't sent any more; lets disconnect - Disconnect(NetConstants.ConnResetMessage); - ptr = 0; - numIncludedMessages = 0; - break; - } - m_statistics.PacketSent(ptr, numIncludedMessages); - numIncludedMessages = 0; - m_throttleDebt += ptr; - ptr = 0; - } - } - - // - // encode message - // - - if (send.FragmentGroupId > 0) - ptr = msg.EncodeFragmented(buffer, ptr, send, mtu); - else - ptr = msg.EncodeUnfragmented(buffer, ptr, send.MessageType, send.SequenceNumber); - numIncludedMessages++; - - if (send.MessageType >= NetMessageType.UserReliableUnordered) - { - // store for reliability - if (send.NumSends == 1) - m_unackedSends.Add(send); - } - else - { - // unreliable message; recycle if all sendings done - int unfin = msg.m_numUnfinishedSendings; - msg.m_numUnfinishedSendings = unfin - 1; - if (unfin <= 1) - m_owner.Recycle(msg); - } - - // room to piggyback some acks? - if (m_acknowledgesToSend.Count > 0) - { - int payloadLeft = (mtu - ptr) - NetPeer.kMaxPacketHeaderSize; - if (payloadLeft > 9) - { - // yes, add them as a regular message - ptr = NetOutgoingMessage.EncodeAcksMessage(m_owner.m_sendBuffer, ptr, this, (payloadLeft - 3)); - - if (m_acknowledgesToSend.Count < 1) - m_nextForceAckTime = double.MaxValue; - } - } - - // when sending disconnect we can finish our own disconnect - if (send.MessageType == NetMessageType.Library && msg.m_libType == NetMessageLibraryType.Disconnect) - { - FinishDisconnect(); - break; - } + sendBuffer[m_sendBufferWritePtr++] = (byte)tuple.Item1; + sendBuffer[m_sendBufferWritePtr++] = (byte)tuple.Item2; + sendBuffer[m_sendBufferWritePtr++] = (byte)(tuple.Item2 >> 8); } - if (ptr > 0) + if (m_queuedAcks.Count > 0) { - bool connectionReset; - m_owner.SendPacket(ptr, m_remoteEndpoint, numIncludedMessages, out connectionReset); - if (connectionReset) - { - // ouch! can't sent any more; lets disconnect - Disconnect(NetConstants.ConnResetMessage); - } - else - { - m_statistics.PacketSent(ptr, numIncludedMessages); - numIncludedMessages = 0; - m_throttleDebt += ptr; - } + // send packet and go for another round of acks + NetException.Assert(m_sendBufferWritePtr > 0 && m_sendBufferNumMessages > 0); + m_peer.SendPacket(m_sendBufferWritePtr, m_remoteEndpoint, m_sendBufferNumMessages, out connectionReset); + m_statistics.PacketSent(m_sendBufferWritePtr, 1); + m_sendBufferWritePtr = 0; + m_sendBufferNumMessages = 0; } } + + // + // send queued messages + // + foreach (NetSenderChannelBase channel in m_sendChannels) + { + NetException.Assert(m_sendBufferWritePtr < 1 || m_sendBufferNumMessages > 0); + if (channel != null) + channel.SendQueuedMessages(now); + NetException.Assert(m_sendBufferWritePtr < 1 || m_sendBufferNumMessages > 0); + } + + // + // Put on wire data has been written to send buffer but not yet sent + // + if (m_sendBufferWritePtr > 0) + { + m_peer.VerifyNetworkThread(); + NetException.Assert(m_sendBufferWritePtr > 0 && m_sendBufferNumMessages > 0); + m_peer.SendPacket(m_sendBufferWritePtr, m_remoteEndpoint, m_sendBufferNumMessages, out connectionReset); + m_statistics.PacketSent(m_sendBufferWritePtr, m_sendBufferNumMessages); + m_sendBufferWritePtr = 0; + m_sendBufferNumMessages = 0; + } } - - internal void HandleUserMessage(double now, NetMessageType mtp, bool isFragment, ushort channelSequenceNumber, int ptr, int payloadLengthBits) + + // Queue an item for immediate sending on the wire + // This method is called from the ISenderChannels + internal void QueueSendMessage(NetOutgoingMessage om, int seqNr) { - m_owner.VerifyNetworkThread(); + m_peer.VerifyNetworkThread(); - m_owner.LogVerbose("Received over wire: " + mtp + "#" + channelSequenceNumber); - try + int sz = om.GetEncodedSize(); + if (sz > m_peerConfiguration.m_maximumTransmissionUnit) + m_peer.LogWarning("Message larger than MTU! Fragmentation must have failed!"); + + if (m_sendBufferWritePtr + sz > m_peerConfiguration.m_maximumTransmissionUnit) { - NetDeliveryMethod ndm = NetPeer.GetDeliveryMethod(mtp); - - // - // Unreliable - // - if (ndm == NetDeliveryMethod.Unreliable) - { - AcceptMessage(mtp, isFragment, channelSequenceNumber, ptr, payloadLengthBits); - return; - } - - // - // UnreliableSequenced - // - if (ndm == NetDeliveryMethod.UnreliableSequenced) - { - bool reject = ReceivedSequencedMessage(mtp, channelSequenceNumber); - if (!reject) - AcceptMessage(mtp, isFragment, channelSequenceNumber, ptr, payloadLengthBits); - return; - } - - // - // Reliable delivery methods below - // - - // queue ack; regardless if this is a duplicate or not - m_acknowledgesToSend.Enqueue((int)channelSequenceNumber | ((int)mtp << 16)); - if (m_nextForceAckTime == double.MaxValue) - m_nextForceAckTime = now + m_peerConfiguration.m_maxAckDelayTime; - - if (ndm == NetDeliveryMethod.ReliableSequenced) - { - bool reject = ReceivedSequencedMessage(mtp, channelSequenceNumber); - if (!reject) - AcceptMessage(mtp, isFragment, channelSequenceNumber, ptr, payloadLengthBits); - return; - } - - // relate to all received up to - int reliableSlot = (int)mtp - (int)NetMessageType.UserReliableUnordered; - int diff = Relate(channelSequenceNumber, m_nextExpectedReliableSequence[reliableSlot]); - - if (diff > (ushort.MaxValue / 2)) - { - // Reject out-of-window - //m_statistics.CountDuplicateMessage(msg); - m_owner.LogVerbose("Rejecting duplicate reliable " + mtp + " " + channelSequenceNumber); - return; - } - - if (diff == 0) - { - // Expected sequence number - AcceptMessage(mtp, isFragment, channelSequenceNumber, ptr, payloadLengthBits); - - ExpectedReliableSequenceArrived(reliableSlot, isFragment); - return; - } - - // - // Early reliable message - we must check if it's already been received - // - // DeliveryMethod is ReliableUnordered or ReliableOrdered here - // - - // get bools list we must check - NetBitVector recList = m_reliableReceived[reliableSlot]; - if (recList == null) - { - recList = new NetBitVector(NetConstants.NumSequenceNumbers); - m_reliableReceived[reliableSlot] = recList; - } - - if (recList[channelSequenceNumber]) - { - // Reject duplicate - //m_statistics.CountDuplicateMessage(msg); - m_owner.LogVerbose("Rejecting duplicate reliable " + ndm.ToString() + channelSequenceNumber.ToString()); - return; - } - - // It's an early reliable message - m_owner.LogVerbose("Received early reliable message: " + channelSequenceNumber); - - // - // It's not a duplicate; mark as received. Release if it's unordered, else withhold - // - recList[channelSequenceNumber] = true; - - if (ndm == NetDeliveryMethod.ReliableUnordered) - { - AcceptMessage(mtp, isFragment, channelSequenceNumber, ptr, payloadLengthBits); - return; - } - - // - // Only ReliableOrdered left here; withhold it - // - - // Early ordered message; withhold - const int orderedSlotsStart = ((int)NetMessageType.UserReliableOrdered - (int)NetMessageType.UserReliableUnordered); - int orderedSlot = reliableSlot - orderedSlotsStart; - - List wmList = m_withheldMessages[orderedSlot]; - if (wmList == null) - { - wmList = new List(); - m_withheldMessages[orderedSlot] = wmList; - } - - // create message - NetIncomingMessage im = m_owner.CreateIncomingMessage(NetIncomingMessageType.Data, m_owner.m_receiveBuffer, ptr, NetUtility.BytesToHoldBits(payloadLengthBits)); - im.m_bitLength = payloadLengthBits; - im.m_messageType = mtp; - im.m_sequenceNumber = channelSequenceNumber; - im.m_senderConnection = this; - im.m_senderEndpoint = m_remoteEndpoint; - if (isFragment) - im.m_fragmentationInfo = s_genericFragmentationInfo; - - m_owner.LogVerbose("Withholding " + im + " (waiting for " + m_nextExpectedReliableSequence[reliableSlot] + ")"); - - wmList.Add(im); - - return; - } - catch (Exception ex) - { -#if DEBUG - throw new NetException("Message generated exception: " + ex, ex); -#else - m_owner.LogError("Message generated exception: " + ex); - return; -#endif - } - } - - private void AcceptMessage(NetMessageType mtp, bool isFragment, ushort seqNr, int ptr, int payloadLengthBits) - { - byte[] buffer = m_owner.m_receiveBuffer; - NetIncomingMessage im; - int bytesLen = NetUtility.BytesToHoldBits(payloadLengthBits); - - if (isFragment) - { - int fragmentGroup = buffer[ptr++] | (buffer[ptr++] << 8); - int fragmentTotalCount = buffer[ptr++] | (buffer[ptr++] << 8); - int fragmentNr = buffer[ptr++] | (buffer[ptr++] << 8); - - // do we already have fragments of this group? - if (!m_fragmentGroups.TryGetValue(fragmentGroup, out im)) - { - // new fragmented message - int estLength = fragmentTotalCount * bytesLen; - - im = m_owner.CreateIncomingMessage(NetIncomingMessageType.Data, estLength); - im.m_messageType = mtp; - im.m_sequenceNumber = seqNr; - im.m_senderConnection = this; - im.m_senderEndpoint = m_remoteEndpoint; - - NetFragmentationInfo info = new NetFragmentationInfo(); - info.TotalFragmentCount = fragmentTotalCount; - info.Received = new bool[fragmentTotalCount]; - info.FragmentSize = bytesLen; - im.m_fragmentationInfo = info; - - m_fragmentGroups[fragmentGroup] = im; - } - - // insert this fragment at correct position - bool done = InsertFragment(im, fragmentNr, ptr, bytesLen); - if (!done) - return; - - // all received! - im.m_fragmentationInfo = null; - m_fragmentGroups.Remove(fragmentGroup); - } - else - { - // non-fragmented - release to application - im = m_owner.CreateIncomingMessage(NetIncomingMessageType.Data, buffer, ptr, bytesLen); - im.m_bitLength = payloadLengthBits; - im.m_messageType = mtp; - im.m_sequenceNumber = seqNr; - im.m_senderConnection = this; - im.m_senderEndpoint = m_remoteEndpoint; + bool connReset; // TODO: handle connection reset + NetException.Assert(m_sendBufferWritePtr > 0 && m_sendBufferNumMessages > 0); // or else the message should have been fragmented earlier + m_peer.SendPacket(m_sendBufferWritePtr, m_remoteEndpoint, m_sendBufferNumMessages, out connReset); + m_statistics.PacketSent(m_sendBufferWritePtr, m_sendBufferNumMessages); + m_sendBufferWritePtr = 0; + m_sendBufferNumMessages = 0; } - m_owner.LogVerbose("Releasing " + im); - m_owner.ReleaseMessage(im); - } + m_sendBufferWritePtr = om.Encode(m_peer.m_sendBuffer, m_sendBufferWritePtr, seqNr); + m_sendBufferNumMessages++; - private bool InsertFragment(NetIncomingMessage im, int nr, int ptr, int payloadLength) - { - NetFragmentationInfo info = im.m_fragmentationInfo; - - if (nr >= info.TotalFragmentCount) - { - m_owner.LogError("Received fragment larger than total fragments! (total " + info.TotalFragmentCount + ", nr " + nr + ")"); - return false; - } - - if (info.Received[nr] == true) - { - // duplicate fragment - return false; - } - - // insert data - int offset = nr * info.FragmentSize; - - if (im.m_data.Length < offset + payloadLength) - { - byte[] arr = im.m_data; - Array.Resize(ref arr, offset + payloadLength); - } - - Buffer.BlockCopy(m_owner.m_receiveBuffer, ptr, im.m_data, offset, payloadLength); - - // only enlarge message length if this is latest fragment received - int newBitLength = (8 * (offset + payloadLength)); - if (newBitLength > im.m_bitLength) - im.m_bitLength = newBitLength; - - info.Received[nr] = true; - info.TotalReceived++; - - m_owner.LogVerbose("Got fragment " + nr + "/" + info.TotalFragmentCount + " (num received: " + info.TotalReceived + ")"); - - return info.TotalReceived >= info.TotalFragmentCount; - } - - internal void HandleLibraryMessage(double now, NetMessageLibraryType libType, int ptr, int payloadLengthBits) - { - m_owner.VerifyNetworkThread(); - - switch (libType) - { - case NetMessageLibraryType.Error: - m_owner.LogWarning("Received NetMessageLibraryType.Error message!"); - break; - case NetMessageLibraryType.Connect: - case NetMessageLibraryType.ConnectResponse: - case NetMessageLibraryType.ConnectionEstablished: - case NetMessageLibraryType.Disconnect: - HandleIncomingHandshake(libType, ptr, payloadLengthBits); - break; - case NetMessageLibraryType.KeepAlive: - // no operation, we just want the acks - break; - case NetMessageLibraryType.Ping: - if (NetUtility.BytesToHoldBits(payloadLengthBits) > 0) - HandleIncomingPing(m_owner.m_receiveBuffer[ptr]); - else - m_owner.LogWarning("Received malformed ping"); - break; - case NetMessageLibraryType.Pong: - if (payloadLengthBits == (9 * 8)) - { - byte pingNr = m_owner.m_receiveBuffer[ptr++]; - double remoteNetTime = BitConverter.ToDouble(m_owner.m_receiveBuffer, ptr); - HandleIncomingPong(now, pingNr, remoteNetTime); - } - else - { - m_owner.LogWarning("Received malformed pong"); - } - break; - case NetMessageLibraryType.Acknowledge: - HandleIncomingAcks(ptr, NetUtility.BytesToHoldBits(payloadLengthBits)); - break; - default: - m_owner.LogWarning("Unhandled library type in " + this + ": " + libType); - break; - } - - return; - } - - internal void SendLibrary(NetOutgoingMessage msg) - { - NetException.Assert(msg.m_libType != NetMessageLibraryType.Error); - - NetSending send = new NetSending(msg, NetMessageType.Library, 0); - - msg.m_wasSent = true; - msg.m_numUnfinishedSendings++; - m_unsentMessages.Enqueue(send); + NetException.Assert(m_sendBufferWritePtr > 0, "Encoded zero size message?"); + NetException.Assert(m_sendBufferNumMessages > 0); } /// - /// Creates a new message for sending + /// Send a message to this remote connection /// - public NetOutgoingMessage CreateMessage() + /// The message to send + /// How to deliver the message + /// Sequence channel within the delivery method + public NetSendResult SendMessage(NetOutgoingMessage msg, NetDeliveryMethod method, int sequenceChannel) { - return m_owner.CreateMessage(); + return m_peer.SendMessage(msg, this, method, sequenceChannel); } - /// - /// Creates a new message for sending - /// - /// initial capacity in bytes - public NetOutgoingMessage CreateMessage(int initialCapacity) + // called by SendMessage() and NetPeer.SendMessage; ie. may be user thread + internal NetSendResult EnqueueMessage(NetOutgoingMessage msg, NetDeliveryMethod method, int sequenceChannel) { - return m_owner.CreateMessage(initialCapacity); + NetMessageType tp = (NetMessageType)((int)method + sequenceChannel); + msg.m_messageType = tp; + + // TODO: do we need to make this more thread safe? + int channelSlot = (int)method - 1 + sequenceChannel; + NetSenderChannelBase chan = m_sendChannels[channelSlot]; + if (chan == null) + chan = CreateSenderChannel(tp); + + if (msg.GetEncodedSize() > m_peerConfiguration.m_maximumTransmissionUnit) + throw new NetException("Message too large! Fragmentation failure?"); + + return chan.Enqueue(msg); } - public bool SendMessage(NetOutgoingMessage msg, NetDeliveryMethod method) + // may be on user thread + private NetSenderChannelBase CreateSenderChannel(NetMessageType tp) { - return SendMessage(msg, method, 0); - } - - public bool SendMessage(NetOutgoingMessage msg, NetDeliveryMethod method, int sequenceChannel) - { - if (msg == null) - throw new ArgumentNullException("msg"); - - NetException.Assert(msg.m_libType == NetMessageLibraryType.Error, "Use SendLibrary() instead!"); - - if (msg.IsSent) - throw new NetException("Message has already been sent!"); - + NetSenderChannelBase chan; + NetDeliveryMethod method = tp.GetDeliveryMethod(); + int sequenceChannel = (int)tp - (int)method; switch (method) { case NetDeliveryMethod.Unreliable: - case NetDeliveryMethod.ReliableUnordered: - if (sequenceChannel != 0) - throw new NetException("Delivery method " + method + " cannot use sequence channels other than 0!"); + case NetDeliveryMethod.UnreliableSequenced: + chan = new NetUnreliableSenderChannel(this, NetConstants.UnreliableWindowSize); break; case NetDeliveryMethod.ReliableOrdered: - case NetDeliveryMethod.ReliableSequenced: - case NetDeliveryMethod.UnreliableSequenced: - NetException.Assert(sequenceChannel >= 0 && sequenceChannel < NetConstants.NetChannelsPerDeliveryMethod, "Sequence channel must be between 0 and NetConstants.NetChannelsPerDeliveryMethod (" + NetConstants.NetChannelsPerDeliveryMethod + ")"); + chan = new NetReliableSenderChannel(this, NetConstants.ReliableOrderedWindowSize); break; - case NetDeliveryMethod.Unknown: + case NetDeliveryMethod.ReliableSequenced: + case NetDeliveryMethod.ReliableUnordered: default: - throw new NetException("Bad delivery method!"); + // + // TODO: this is placeholder! + // + chan = new NetReliableSenderChannel(this, 64); + break; } - if (m_owner == null) - return false; // we've been disposed + int channelSlot = (int)method - 1 + sequenceChannel; + NetException.Assert(m_sendChannels[channelSlot] == null); + m_sendChannels[channelSlot] = chan; - msg.m_wasSent = true; - - NetMessageType tp = (NetMessageType)((int)method + sequenceChannel); - return EnqueueSendMessage(msg, tp); + return chan; } - internal bool EnqueueSendMessage(NetOutgoingMessage msg, NetMessageType tp) - { - int msgLen = msg.LengthBytes; - int mtu = m_owner.m_configuration.m_maximumTransmissionUnit; - - if (msgLen <= mtu) - { - NetSending send = new NetSending(msg, tp, GetSendSequenceNumber(tp)); - msg.m_numUnfinishedSendings++; - - send.SetNextResend(this); - - m_unsentMessages.Enqueue(send); - return true; - } - -#if DEBUG - if (tp < NetMessageType.UserReliableUnordered) - { - // unreliable - m_owner.LogWarning("Sending more than MTU (currently " + mtu + ") bytes unreliably is not recommended!"); - } -#endif - mtu -= NetConstants.FragmentHeaderSize; // size of fragmentation info - - // message must be fragmented - int fgi = Interlocked.Increment(ref m_nextFragmentGroupId); - // TODO: loop group id? - - int numFragments = (msgLen + mtu - 1) / mtu; - - for (int i = 0; i < numFragments; i++) - { - int flen = (i == numFragments - 1 ? (msgLen - (mtu * (numFragments - 1))) : mtu); - - NetSending fs = new NetSending(msg, tp, GetSendSequenceNumber(tp)); - fs.FragmentGroupId = fgi; - fs.FragmentNumber = i; - fs.FragmentTotalCount = numFragments; - msg.m_numUnfinishedSendings++; - m_unsentMessages.Enqueue(fs); - fs.SetNextResend(this); - } - - return true; - } - - public void Disconnect(string byeMessage) + // received a library message while Connected + internal void ReceivedLibraryMessage(NetMessageType tp, int ptr, int payloadLength) { - // called on user thread (possibly) - if (m_status == NetConnectionStatus.None || m_status == NetConnectionStatus.Disconnected) - return; + m_peer.VerifyNetworkThread(); - m_owner.LogVerbose("Disconnect requested for " + this); - m_disconnectByeMessage = byeMessage; + float now = (float)NetTime.Now; - if (m_status != NetConnectionStatus.Disconnected && m_status != NetConnectionStatus.None) - SetStatus(NetConnectionStatus.Disconnecting, byeMessage); + switch (tp) + { + case NetMessageType.Disconnect: + NetIncomingMessage msg = m_peer.SetupReadHelperMessage(ptr, payloadLength); + ExecuteDisconnect(msg.ReadString(), false); + break; + case NetMessageType.Acknowledge: + for (int i = 0; i < payloadLength; i+=3) + { + NetMessageType acktp = (NetMessageType)m_peer.m_receiveBuffer[ptr++]; // netmessagetype + int seqNr = m_peer.m_receiveBuffer[ptr++]; + seqNr |= (m_peer.m_receiveBuffer[ptr++] << 8); - // loosen up throttling - m_throttleDebt = -m_owner.m_configuration.m_throttlePeakBytes; + NetSenderChannelBase chan = m_sendChannels[(int)acktp - 1]; + if (chan == null) + chan = CreateSenderChannel(acktp); - // instantly resend all unacked - double now = NetTime.Now; - foreach(NetSending send in m_unackedSends) - send.NextResend = now; + //m_peer.LogVerbose("Received ack for " + acktp + "#" + seqNr); - NetOutgoingMessage bye = m_owner.CreateLibraryMessage(NetMessageLibraryType.Disconnect, byeMessage); - SendLibrary(bye); + chan.ReceiveAcknowledge(now, seqNr); + } + break; + case NetMessageType.Ping: + int pingNr = m_peer.m_receiveBuffer[ptr++]; + SendPong(pingNr); + break; + case NetMessageType.Pong: + int pongNr = m_peer.m_receiveBuffer[ptr++]; + ReceivedPong(now, pongNr); + break; + default: + m_peer.LogWarning("Connection received unhandled library message: " + tp); + break; + } } - public void Approve() + internal void ReceivedMessage(NetIncomingMessage msg) { - if (!m_peerConfiguration.IsMessageTypeEnabled(NetIncomingMessageType.ConnectionApproval)) - m_owner.LogError("Approve() called but ConnectionApproval is not enabled in NetPeerConfiguration!"); + m_peer.VerifyNetworkThread(); - if (m_pendingStatus != PendingConnectionStatus.Pending) + NetMessageType tp = msg.m_receivedMessageType; + + int channelSlot = (int)tp - 1; + NetReceiverChannelBase chan = m_receiveChannels[channelSlot]; + if (chan == null) + chan = CreateReceiverChannel(tp); + + chan.ReceiveMessage(msg); + } + + private NetReceiverChannelBase CreateReceiverChannel(NetMessageType tp) + { + m_peer.VerifyNetworkThread(); + + // create receiver channel + NetReceiverChannelBase chan; + NetDeliveryMethod method = tp.GetDeliveryMethod(); + switch (method) { - m_owner.LogWarning("Approve() called on non-pending connection!"); + case NetDeliveryMethod.Unreliable: + chan = new NetUnreliableUnorderedReceiver(this); + break; + case NetDeliveryMethod.ReliableOrdered: + chan = new NetReliableOrderedReceiver(this, NetConstants.ReliableOrderedWindowSize); + break; + case NetDeliveryMethod.UnreliableSequenced: + chan = new NetUnreliableSequencedReceiver(this); + break; + case NetDeliveryMethod.ReliableUnordered: + chan = new NetReliableUnorderedReceiver(this, NetConstants.ReliableOrderedWindowSize); + break; + case NetDeliveryMethod.ReliableSequenced: + chan = new NetReliableSequencedReceiver(this, NetConstants.ReliableSequencedWindowSize); + break; + default: + throw new NetException("Unhandled NetDeliveryMethod!"); + } + + int channelSlot = (int)tp - 1; + NetException.Assert(m_receiveChannels[channelSlot] == null); + m_receiveChannels[channelSlot] = chan; + + return chan; + } + + internal void QueueAck(NetMessageType tp, int sequenceNumber) + { + m_queuedAcks.Enqueue(new NetTuple(tp, sequenceNumber)); + } + + /// + /// Zero windowSize indicates that the channel is not yet instantiated (used) + /// Negative freeWindowSlots means this amount of messages are currently queued but delayed due to closed window + /// + public void GetSendQueueInfo(NetDeliveryMethod method, int sequenceChannel, out int windowSize, out int freeWindowSlots) + { + int channelSlot = (int)method - 1 + sequenceChannel; + var chan = m_sendChannels[channelSlot]; + if (chan == null) + { + windowSize = 0; + freeWindowSlots = 0; return; } - m_pendingStatus = PendingConnectionStatus.Approved; + + windowSize = chan.WindowSize; + freeWindowSlots = chan.GetAllowedSends() - chan.m_queuedSends.Count; + return; } - public void Deny(string reason) + internal void Shutdown(string reason) { - if (!m_peerConfiguration.IsMessageTypeEnabled(NetIncomingMessageType.ConnectionApproval)) - m_owner.LogError("Deny() called but ConnectionApproval is not enabled in NetPeerConfiguration!"); - - if (m_pendingStatus != PendingConnectionStatus.Pending) - { - m_owner.LogWarning("Deny() called on non-pending connection!"); - return; - } - m_pendingStatus = PendingConnectionStatus.Denied; - m_pendingDenialReason = reason; + ExecuteDisconnect(reason, true); } public override string ToString() { - return "[NetConnection to " + m_remoteEndpoint + " Status: " + m_visibleStatus + "]"; + return "[NetConnection to " + m_remoteEndpoint + "]"; } } -} \ No newline at end of file +} diff --git a/Lidgren.Network/NetConnectionStatistics.cs b/Lidgren.Network/NetConnectionStatistics.cs index b3b2d00..a7e8081 100644 --- a/Lidgren.Network/NetConnectionStatistics.cs +++ b/Lidgren.Network/NetConnectionStatistics.cs @@ -23,6 +23,9 @@ using System.Diagnostics; namespace Lidgren.Network { + /// + /// Statistics for a NetConnection instance + /// public sealed class NetConnectionStatistics { private readonly NetConnection m_connection; @@ -77,23 +80,12 @@ namespace Lidgren.Network /// public int ResentMessages { get { return m_resentMessages; } } - public double LastSendRespondedTo { get { return m_connection.m_lastSendRespondedTo; } } - - public int MostSends - { - get - { - int most = 0; - foreach (var a in m_connection.m_unackedSends) - if (a.NumSends > most) - most = a.NumSends; - return most; - } - } + // public double LastSendRespondedTo { get { return m_connection.m_lastSendRespondedTo; } } [Conditional("DEBUG")] internal void PacketSent(int numBytes, int numMessages) { + NetException.Assert(numBytes > 0 && numMessages > 0); m_sentPackets++; m_sentBytes += numBytes; m_sentMessages += numMessages; @@ -102,6 +94,7 @@ namespace Lidgren.Network [Conditional("DEBUG")] internal void PacketReceived(int numBytes, int numMessages) { + NetException.Assert(numBytes > 0 && numMessages > 0); m_receivedPackets++; m_receivedBytes += numBytes; m_receivedMessages += numMessages; @@ -116,24 +109,47 @@ namespace Lidgren.Network public override string ToString() { StringBuilder bdr = new StringBuilder(); - bdr.AppendLine("Average roundtrip time: " + NetTime.ToReadable(m_connection.m_averageRoundtripTime)); + //bdr.AppendLine("Average roundtrip time: " + NetTime.ToReadable(m_connection.m_averageRoundtripTime)); bdr.AppendLine("Sent " + m_sentBytes + " bytes in " + m_sentMessages + " messages in " + m_sentPackets + " packets"); bdr.AppendLine("Received " + m_receivedBytes + " bytes in " + m_receivedMessages + " messages in " + m_receivedPackets + " packets"); if (m_resentMessages > 0) bdr.AppendLine("Resent messages: " + m_resentMessages); - int numUnsent = m_connection.m_unsentMessages.Count; - if (numUnsent > 0) - bdr.AppendLine("Unsent messages: " + numUnsent); - int numStored = m_connection.GetStoredMessagesCount(); - if (numStored > 0) - bdr.AppendLine("Stored messages: " + numStored); - int numWithheld = m_connection.GetWithheldMessagesCount(); - if (numWithheld > 0) - bdr.AppendLine("Withheld messages: " + numWithheld); + int numUnsent = 0; + int numStored = 0; + foreach (NetSenderChannelBase sendChan in m_connection.m_sendChannels) + { + if (sendChan == null) + continue; + numUnsent += sendChan.m_queuedSends.Count; + + var relSendChan = sendChan as NetReliableSenderChannel; + if (relSendChan != null) + { + for (int i = 0; i < relSendChan.m_storedMessages.Length; i++) + if (relSendChan.m_storedMessages[i].Message != null) + numStored++; + } + } + + int numWithheld = 0; + foreach (NetReceiverChannelBase recChan in m_connection.m_receiveChannels) + { + var relRecChan = recChan as NetReliableOrderedReceiver; + if (relRecChan != null) + { + for (int i = 0; i < relRecChan.m_withheldMessages.Length; i++) + if (relRecChan.m_withheldMessages[i] != null) + numWithheld++; + } + } + + bdr.AppendLine("Unsent messages: " + numUnsent); + bdr.AppendLine("Stored messages: " + numStored); + bdr.AppendLine("Withheld messages: " + numWithheld); return bdr.ToString(); } } -} +} \ No newline at end of file diff --git a/Lidgren.Network/NetConnectionStatus.cs b/Lidgren.Network/NetConnectionStatus.cs index 7169538..e5a9338 100644 --- a/Lidgren.Network/NetConnectionStatus.cs +++ b/Lidgren.Network/NetConnectionStatus.cs @@ -21,13 +21,17 @@ using System; namespace Lidgren.Network { /// - /// Status of a connection + /// Status for a NetConnection instance /// public enum NetConnectionStatus { None, - Connecting, - Connected, + + InitiatedConnect, // we sent Connect + RespondedConnect, // we got Connect, sent ConnectResponse + + Connected, // we received ConnectResponse (if initiator) or ConnectionEstablished (if passive) + Disconnecting, Disconnected } diff --git a/Lidgren.Network/NetConstants.cs b/Lidgren.Network/NetConstants.cs index 1b317bf..cde24df 100644 --- a/Lidgren.Network/NetConstants.cs +++ b/Lidgren.Network/NetConstants.cs @@ -20,27 +20,35 @@ using System; namespace Lidgren.Network { + /// + /// All the constants used when compiling the library + /// public static class NetConstants { + public const int NumTotalChannels = 99; + public const int NetChannelsPerDeliveryMethod = 32; - public const int NumSequenceNumbers = ushort.MaxValue + 1; // 0 is a valid sequence number + public const int NumSequenceNumbers = 1024; + + public const int HeaderByteSize = 5; + + public const int UnreliableWindowSize = 128; + public const int ReliableOrderedWindowSize = 64; + public const int ReliableSequencedWindowSize = 64; + + public const int MaxFragmentationGroups = ushort.MaxValue - 1; /// /// Number of channels which needs a sequence number to work /// - internal const int NumSequencedChannels = ((int)NetMessageType.UserReliableOrdered + NetConstants.NetChannelsPerDeliveryMethod) - (int)NetMessageType.UserSequenced; + internal const int NumSequencedChannels = ((int)NetMessageType.UserReliableOrdered1 + NetConstants.NetChannelsPerDeliveryMethod) - (int)NetMessageType.UserSequenced1; /// /// Number of reliable channels /// - internal const int NumReliableChannels = ((int)NetMessageType.UserReliableOrdered + NetConstants.NetChannelsPerDeliveryMethod) - (int)NetMessageType.UserReliableUnordered; - - /// - /// Number of bytes added when message is really a fragment - /// - internal const int FragmentHeaderSize = 6; - + internal const int NumReliableChannels = ((int)NetMessageType.UserReliableOrdered1 + NetConstants.NetChannelsPerDeliveryMethod) - (int)NetMessageType.UserReliableUnordered; + internal const string ConnResetMessage = "Connection was reset by remote host"; } } diff --git a/Lidgren.Network/NetDeliveryMethod.cs b/Lidgren.Network/NetDeliveryMethod.cs new file mode 100644 index 0000000..527f1ad --- /dev/null +++ b/Lidgren.Network/NetDeliveryMethod.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Lidgren.Network +{ + /// + /// How the library deals with resends and handling of late messages + /// + public enum NetDeliveryMethod : byte + { + // + // Actually a publicly visible subset of NetMessageType + // + Unknown = 0, + Unreliable = 1, + UnreliableSequenced = 2, + ReliableUnordered = 34, + ReliableSequenced = 35, + ReliableOrdered = 67, + } +} diff --git a/Lidgren.Network/NetEncryption.cs b/Lidgren.Network/NetEncryption.cs index 65f04c5..bf71a34 100644 --- a/Lidgren.Network/NetEncryption.cs +++ b/Lidgren.Network/NetEncryption.cs @@ -75,7 +75,7 @@ namespace Lidgren.Network /// String to hash for key /// public NetXtea(string key) - : this(NetSha.Hash(Encoding.ASCII.GetBytes(key)), 32) + : this(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key)), 32) { } @@ -138,195 +138,4 @@ namespace Lidgren.Network destination[destinationOffset++] = (byte)value; } } - - public static class NetSha - { - // TODO: switch to SHA256 - private static SHA1 m_sha; - private static object s_lock = new object(); - - public static byte[] Hash(byte[] data) - { - lock (s_lock) - { - if (m_sha == null) - m_sha = SHA1Managed.Create(); - return m_sha.ComputeHash(data); - } - } - } - - public static class NetSRP - { - public static readonly BigInteger N = new BigInteger(NetUtility.ToByteArray("0115b8b692e0e045692cf280b436735c77a5a9e8a9e7ed56c965f87db5b2a2ece3")); - public static readonly BigInteger g = new BigInteger((uint)2); - public static readonly BigInteger k = ComputeMultiplier(); - - /// - /// Compute multiplier (k) - /// - private static BigInteger ComputeMultiplier() - { - string one = NetUtility.ToHexString(N.GetBytes()); - string two = NetUtility.ToHexString(g.GetBytes()); - byte[] cc = NetUtility.ToByteArray(one + two.PadLeft(one.Length, '0')); - BigInteger retval = BigInteger.Modulus(new BigInteger(NetSha.Hash(cc)), N); - return retval; - } - - /// - /// Creates a verifier that the server can use to authenticate users later on (v) - /// - public static void ComputePasswordVerifier(string username, string password, byte[] salt, out byte[] serverVerifier, out byte[] clientVerifier) - { - byte[] tmp = Encoding.ASCII.GetBytes(username + ":" + password); - byte[] innerHash = NetSha.Hash(tmp); - - byte[] total = new byte[innerHash.Length + salt.Length]; - Buffer.BlockCopy(salt, 0, total, 0, salt.Length); - Buffer.BlockCopy(innerHash, 0, total, salt.Length, innerHash.Length); - - clientVerifier = NetSha.Hash(total); - - // Verifier (v) = g^x (mod N) - BigInteger xx = new BigInteger(clientVerifier); - serverVerifier = g.ModPow(xx, N).GetBytes(); - - return; - } - - /// - /// Get 256 random bits - /// - public static byte[] CreateRandomKey() - { - byte[] retval = new byte[32]; - NetRandom.Instance.NextBytes(retval); - return retval; - } - - /// - /// Gets 80 random bits - /// - public static byte[] CreateRandomSalt() - { - byte[] retval = new byte[10]; - NetRandom.Instance.NextBytes(retval); - return retval; - } - - /// - /// Compute client challenge (A) - /// - public static byte[] ComputeClientPublicKey(byte[] clientPrivateKey) // a - { - BigInteger a = new BigInteger(clientPrivateKey); - - BigInteger retval = g.ModPow(a, N); - - string gs = NetUtility.ToHexString(g.GetBytes()); - - - Console.WriteLine("a: " + NetUtility.ToHexString(a.GetBytes())); - Console.WriteLine("A: " + NetUtility.ToHexString(retval.GetBytes())); - - return retval.GetBytes(); - } - - /// - /// Compute server challenge (B) - /// - public static byte[] ComputeServerPublicKey(byte[] serverPrivateKey, byte[] verifier) // b - { - BigInteger salt = new BigInteger(serverPrivateKey); - - var bb = g.ModPow(salt, N); - var B = BigInteger.Modulus((bb + (new BigInteger(verifier) * k)), N); - - return B.GetBytes(); - } - - public static byte[] ComputeU(byte[] clientPublicKey, byte[] serverPublicKey) // u - { - byte[] A = clientPublicKey; - byte[] B = serverPublicKey; - - string one = NetUtility.ToHexString(A); - string two = NetUtility.ToHexString(B); - string compound = one.PadLeft(66, '0') + two.PadLeft(66, '0'); - - byte[] cc = NetUtility.ToByteArray(compound); - - return NetSha.Hash(cc); - } - - public static byte[] ComputeServerSessionKey(byte[] clientPublicKey, byte[] verifier, byte[] u, byte[] serverPrivateKey) // Ss - { - // S = (Av^u) ^ b (mod N) - // return vv.modPow(uu, N).multiply(A).mod(N).modPow(bb, N); - - BigInteger verBi = new BigInteger(verifier); - BigInteger uBi = new BigInteger(u); - BigInteger ABi = new BigInteger(clientPublicKey); // A - BigInteger bBi = new BigInteger(serverPrivateKey); // b - - Console.WriteLine("Ss input v: " + NetUtility.ToHexString(verifier)); - Console.WriteLine("Ss input u: " + NetUtility.ToHexString(u)); - Console.WriteLine("Ss input A: " + NetUtility.ToHexString(clientPublicKey)); - Console.WriteLine("Ss input A: " + ABi.ToString(16)); - Console.WriteLine("Ss input b: " + NetUtility.ToHexString(serverPrivateKey)); - - BigInteger retval = verBi.ModPow(uBi, N).Multiply(ABi).Modulus(N).ModPow(bBi, N).Modulus(N); - Console.WriteLine("Ss (trad): " + NetUtility.ToHexString(retval.GetBytes())); - BigInteger f1 = verBi.ModPow(uBi, N); - Console.WriteLine("f1 (trad): " + NetUtility.ToHexString(f1.GetBytes())); - - //return retval.GetBytes(); - - - // own - // BigInteger tmp1 = verBi.ModPow(uBi, N).ModPow(bBi, N).Modulus(N); - BigInteger tmp1 = (ABi * verBi.ModPow(uBi, N)).ModPow(bBi, N); - Console.WriteLine("Ss (own): " + NetUtility.ToHexString(tmp1.GetBytes())); - - - - // bc - BigIntegerBC verBi2 = new BigIntegerBC(verifier); - BigIntegerBC ABi2 = new BigIntegerBC(clientPublicKey); // A - BigIntegerBC uBi2 = new BigIntegerBC(u); - BigIntegerBC bBi2 = new BigIntegerBC(serverPrivateKey); - BigIntegerBC N2 = new BigIntegerBC(N.GetBytes()); - - BigIntegerBC retval2 = verBi2.ModPow(uBi2, N2).Multiply(ABi2).Modulus(N2).ModPow(bBi2, N2).Modulus(N2); - Console.WriteLine("Ss (bc): " + NetUtility.ToHexString(retval2.ToByteArray())); - BigIntegerBC f12 = verBi2.ModPow(uBi2, N2); - Console.WriteLine("f1 (bc): " + NetUtility.ToHexString(f12.ToByteArray())); - - - // own bc - BigIntegerBC tmp2 = verBi2.ModPow(uBi2, N2).ModPow(bBi2, N2).Modulus(N2); - Console.WriteLine("Ss (ownBC): " + NetUtility.ToHexString(tmp2.ToByteArray())); - - - - return retval.GetBytes(); - - //return NetSha.Hash(retval.GetBytes()); - } - - public static byte[] ComputeClientSessionKey(byte[] serverPublicKey, byte[] x, byte[] u, byte[] clientPrivateKey) // Sc - { - BigInteger xBi = new BigInteger(x); - BigInteger BBi = new BigInteger(serverPublicKey); // B - BigInteger uBi = new BigInteger(u); - BigInteger aBi = new BigInteger(clientPrivateKey); // a - - BigInteger retval = (BBi + (N - ((k * g.ModPow(xBi, N)) % N))).ModPow(aBi + uBi * xBi, N); - - return retval.GetBytes(); - - //return NetSha.Hash(retval.GetBytes()); - } - } } diff --git a/Lidgren.Network/NetException.cs b/Lidgren.Network/NetException.cs index 13e9d41..bb89261 100644 --- a/Lidgren.Network/NetException.cs +++ b/Lidgren.Network/NetException.cs @@ -15,7 +15,6 @@ PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ using System; using System.Diagnostics; @@ -23,6 +22,9 @@ using System.Runtime.Serialization; namespace Lidgren.Network { + /// + /// Exception thrown in the Lidgren Network Library + /// [Serializable] public sealed class NetException : Exception { diff --git a/Lidgren.Network/NetFragmentationHelper.cs b/Lidgren.Network/NetFragmentationHelper.cs new file mode 100644 index 0000000..d502a60 --- /dev/null +++ b/Lidgren.Network/NetFragmentationHelper.cs @@ -0,0 +1,174 @@ +using System; + +namespace Lidgren.Network +{ + internal static class NetFragmentationHelper + { + internal static int WriteHeader( + byte[] destination, + int ptr, + int group, + int totalBits, + int chunkByteSize, + int chunkNumber) + { + uint num1 = (uint)group; + while (num1 >= 0x80) + { + destination[ptr++] = (byte)(num1 | 0x80); + num1 = num1 >> 7; + } + destination[ptr++] = (byte)num1; + + // write variable length fragment total bits + uint num2 = (uint)totalBits; + while (num2 >= 0x80) + { + destination[ptr++] = (byte)(num2 | 0x80); + num2 = num2 >> 7; + } + destination[ptr++] = (byte)num2; + + // write variable length fragment chunk size + uint num3 = (uint)chunkByteSize; + while (num3 >= 0x80) + { + destination[ptr++] = (byte)(num3 | 0x80); + num3 = num3 >> 7; + } + destination[ptr++] = (byte)num3; + + // write variable length fragment chunk number + uint num4 = (uint)chunkNumber; + while (num4 >= 0x80) + { + destination[ptr++] = (byte)(num4 | 0x80); + num4 = num4 >> 7; + } + destination[ptr++] = (byte)num4; + + return ptr; + } + + internal static int ReadHeader(byte[] buffer, int ptr, out int group, out int totalBits, out int chunkByteSize, out int chunkNumber) + { + int num1 = 0; + int num2 = 0; + while (true) + { + byte num3 = buffer[ptr++]; + num1 |= (num3 & 0x7f) << (num2 & 0x1f); + num2 += 7; + if ((num3 & 0x80) == 0) + { + group = num1; + break; + } + } + + num1 = 0; + num2 = 0; + while (true) + { + byte num3 = buffer[ptr++]; + num1 |= (num3 & 0x7f) << (num2 & 0x1f); + num2 += 7; + if ((num3 & 0x80) == 0) + { + totalBits = num1; + break; + } + } + + num1 = 0; + num2 = 0; + while (true) + { + byte num3 = buffer[ptr++]; + num1 |= (num3 & 0x7f) << (num2 & 0x1f); + num2 += 7; + if ((num3 & 0x80) == 0) + { + chunkByteSize = num1; + break; + } + } + + num1 = 0; + num2 = 0; + while (true) + { + byte num3 = buffer[ptr++]; + num1 |= (num3 & 0x7f) << (num2 & 0x1f); + num2 += 7; + if ((num3 & 0x80) == 0) + { + chunkNumber = num1; + break; + } + } + + return ptr; + } + + internal static int GetFragmentationHeaderSize(int groupId, int totalBytes, int chunkByteSize, int numChunks) + { + int len = 4; + + // write variable length fragment group id + uint num1 = (uint)groupId; + while (num1 >= 0x80) + { + len++; + num1 = num1 >> 7; + } + + // write variable length fragment total bits + uint num2 = (uint)(totalBytes * 8); + while (num2 >= 0x80) + { + len++; + num2 = num2 >> 7; + } + + // write variable length fragment chunk byte size + uint num3 = (uint)chunkByteSize; + while (num3 >= 0x80) + { + len++; + num3 = num3 >> 7; + } + + // write variable length fragment chunk number + uint num4 = (uint)numChunks; + while (num4 >= 0x80) + { + len++; + num4 = num4 >> 7; + } + + return len; + } + + internal static int GetBestChunkSize(int group, int totalBytes, int mtu) + { + int tryNumChunks = (totalBytes / (mtu - 8)) + 1; + int tryChunkSize = (totalBytes / tryNumChunks) + 1; // +1 since we immediately decrement it in the loop + + int headerSize = 0; + do + { + tryChunkSize--; // keep reducing chunk size until it fits within MTU including header + + int numChunks = totalBytes / tryChunkSize; + if (numChunks * tryChunkSize < totalBytes) + numChunks++; + + headerSize = GetFragmentationHeaderSize(group, totalBytes, tryChunkSize, numChunks); + + } while (tryChunkSize + headerSize + 5 + 1 >= mtu); + + return tryChunkSize; + } + } +} diff --git a/Lidgren.Network/NetIncomingMessage.Peek.cs b/Lidgren.Network/NetIncomingMessage.Peek.cs index 66e18bd..f7b45d6 100644 --- a/Lidgren.Network/NetIncomingMessage.Peek.cs +++ b/Lidgren.Network/NetIncomingMessage.Peek.cs @@ -235,7 +235,7 @@ namespace Lidgren.Network byte[] bytes = PeekBytes(8); return BitConverter.ToDouble(bytes, 0); // endianness is handled inside BitConverter.ToSingle } - + /// /// Reads a string /// diff --git a/Lidgren.Network/NetIncomingMessage.Read.Reflection.cs b/Lidgren.Network/NetIncomingMessage.Read.Reflection.cs index 99f1548..e5b44bc 100644 --- a/Lidgren.Network/NetIncomingMessage.Read.Reflection.cs +++ b/Lidgren.Network/NetIncomingMessage.Read.Reflection.cs @@ -41,7 +41,7 @@ namespace Lidgren.Network Type tp = target.GetType(); FieldInfo[] fields = tp.GetFields(flags); - SortMembersList(fields); + NetUtility.SortMembersList(fields); foreach (FieldInfo fi in fields) { @@ -81,7 +81,7 @@ namespace Lidgren.Network Type tp = target.GetType(); PropertyInfo[] fields = tp.GetProperties(flags); - SortMembersList(fields); + NetUtility.SortMembersList(fields); foreach (PropertyInfo fi in fields) { object value; @@ -99,44 +99,5 @@ namespace Lidgren.Network } } } - - // shell sort - internal static void SortMembersList(MemberInfo[] list) - { - int h; - int j; - MemberInfo tmp; - - h = 1; - while (h * 3 + 1 <= list.Length) - h = 3 * h + 1; - - while (h > 0) - { - for (int i = h - 1; i < list.Length; i++) - { - tmp = list[i]; - j = i; - while (true) - { - if (j >= h) - { - if (string.Compare(list[j - h].Name, tmp.Name, StringComparison.InvariantCulture) > 0) - { - list[j] = list[j - h]; - j -= h; - } - else - break; - } - else - break; - } - - list[j] = tmp; - } - h /= 3; - } - } } } diff --git a/Lidgren.Network/NetIncomingMessage.Read.cs b/Lidgren.Network/NetIncomingMessage.Read.cs index 6ead9e1..d242514 100644 --- a/Lidgren.Network/NetIncomingMessage.Read.cs +++ b/Lidgren.Network/NetIncomingMessage.Read.cs @@ -30,12 +30,12 @@ namespace Lidgren.Network private static readonly Dictionary s_readMethods; - private int m_readPosition; + internal int m_readPosition; /// /// Gets or sets the read position in the buffer, in bits (not bytes) /// - public override long Position // override of Stream property + public long Position { get { return (long)m_readPosition; } set { m_readPosition = (int)value; } @@ -62,7 +62,7 @@ namespace Lidgren.Network string n = mi.Name.Substring(4); foreach (Type it in integralTypes) { - if (it.Name == n && mi.ReturnType.Name == it.Name) + if (it.Name == n) s_readMethods[it] = mi; } } @@ -83,7 +83,7 @@ namespace Lidgren.Network // // 8 bit // - public new byte ReadByte() + public byte ReadByte() { NetException.Assert(m_bitLength - m_readPosition >= 8, c_readOverflowError); byte retval = NetBitWriter.ReadByte(m_data, 8, m_readPosition); diff --git a/Lidgren.Network/NetIncomingMessage.Stream.cs b/Lidgren.Network/NetIncomingMessage.Stream.cs deleted file mode 100644 index 6f3b8fb..0000000 --- a/Lidgren.Network/NetIncomingMessage.Stream.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using System.IO; - -namespace Lidgren.Network -{ - public partial class NetIncomingMessage : Stream - { - public override bool CanRead { get { return true; } } - public override bool CanSeek { get { return true; } } - public override bool CanWrite { get { return false; } } - - public override void Flush() - { - // no op - } - - /// - /// Gets the length in bytes - /// - public override long Length - { - get { return LengthBytes; } - } - - public override int Read(byte[] buffer, int offset, int count) - { - // limit amount to remaining - int remainingBytes = NetUtility.BytesToHoldBits(m_bitLength - m_readPosition); - if (count > remainingBytes) - count = remainingBytes; - if (count < 1) - return 0; - - ReadBytes(buffer, offset, count); - return count; - } - - /// - /// Sets the position in the stream, in bytes - /// - public override long Seek(long offset, SeekOrigin origin) - { - switch (origin) - { - case SeekOrigin.Begin: - Position = (offset * 8); - break; - case SeekOrigin.Current: - Position = Position + (offset * 8); - break; - case SeekOrigin.End: - Position = (LengthBytes - offset) * 8; - break; - default: - throw new NotImplementedException("Bad SeekOrigin"); - } - return Position; - } - - public override void SetLength(long value) - { - throw new NetException("It's not possible to set the length of the NetIncomingMessage"); - } - } -} diff --git a/Lidgren.Network/NetIncomingMessage.Write.cs b/Lidgren.Network/NetIncomingMessage.Write.cs index 5a641df..bce7c3a 100644 --- a/Lidgren.Network/NetIncomingMessage.Write.cs +++ b/Lidgren.Network/NetIncomingMessage.Write.cs @@ -88,12 +88,7 @@ namespace Lidgren.Network m_bitLength += bits; } - public override void Write(byte[] source, int offsetInBytes, int numberOfBytes) - { - throw new NetException("NetIncomingMessage does not support writing!"); - } - - internal void WriteBytes(byte[] source, int offsetInBytes, int numberOfBytes) + internal void Write(byte[] source, int offsetInBytes, int numberOfBytes) { if (source == null) throw new ArgumentNullException("source"); diff --git a/Lidgren.Network/NetIncomingMessage.cs b/Lidgren.Network/NetIncomingMessage.cs index def0d59..4d93f4d 100644 --- a/Lidgren.Network/NetIncomingMessage.cs +++ b/Lidgren.Network/NetIncomingMessage.cs @@ -17,77 +17,40 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR TH USE OR OTHER DEALINGS IN THE SOFTWARE. */ using System; -using System.Diagnostics; using System.Net; +using System.Diagnostics; namespace Lidgren.Network { - internal enum NetIncomingMessageReleaseStatus - { - NotReleased = 0, - ReleasedToApplication, - RecycledByApplication - } - - [DebuggerDisplay("{m_readPosition} of {m_bitLength} bits ({LengthBytes} bytes) read")] + /// + /// Incoming message either sent from a remote peer or generated within the library + /// + [DebuggerDisplay("Type={MessageType} LengthBits={LengthBits}")] public partial class NetIncomingMessage { internal byte[] m_data; internal int m_bitLength; - internal NetMessageType m_messageType; // NetDeliveryMethod and sequence channel can be derived from this - internal ushort m_sequenceNumber; - internal NetIncomingMessageReleaseStatus m_status; - - internal NetIncomingMessageType m_incomingType; + internal NetIncomingMessageType m_incomingMessageType; internal IPEndPoint m_senderEndpoint; internal NetConnection m_senderConnection; - - internal NetFragmentationInfo m_fragmentationInfo; + internal int m_sequenceNumber; + internal NetMessageType m_receivedMessageType; + internal bool m_isFragment; /// - /// Gets the length of the data in number of bytes + /// Gets the type of this incoming message /// - public int LengthBytes - { - get { return ((m_bitLength + 7) >> 3); } - } + public NetIncomingMessageType MessageType { get { return m_incomingMessageType; } } /// - /// Gets the length of the data in number of bits + /// Gets the delivery method this message was sent with (if user data) /// - public int LengthBits - { - get { return m_bitLength; } - } + public NetDeliveryMethod DeliveryMethod { get { return m_receivedMessageType.GetDeliveryMethod(); } } /// - /// Returns the internal data buffer, don't modify + /// Gets the sequence channel this message was sent with (if user data) /// - public byte[] PeekDataBuffer() - { - return m_data; - } - - /// - /// Gets the NetDeliveryMethod used by this message - /// - public NetDeliveryMethod DeliveryMethod - { - get { return NetPeer.GetDeliveryMethod(m_messageType); } - } - - /// - /// Gets which sequence channel this message was sent in - /// - public int SequenceChannel - { - get { return (int)m_messageType - (int)NetPeer.GetDeliveryMethod(m_messageType); } - } - - /// - /// Type of data contained in this message - /// - public NetIncomingMessageType MessageType { get { return m_incomingType; } } + public int SequenceChannel { get { return (int)m_receivedMessageType - (int)m_receivedMessageType.GetDeliveryMethod(); } } /// /// IPEndPoint of sender, if any @@ -99,22 +62,40 @@ namespace Lidgren.Network /// public NetConnection SenderConnection { get { return m_senderConnection; } } + /// + /// Gets the length of the message payload in bytes + /// + public int LengthBytes + { + get { return ((m_bitLength + 7) >> 3); } + } + + /// + /// Gets the length of the message payload in bits + /// + public int LengthBits + { + get { return m_bitLength; } + internal set { m_bitLength = value; } + } + internal NetIncomingMessage() { } - internal NetIncomingMessage(byte[] data, int dataLength) + internal NetIncomingMessage(NetIncomingMessageType tp) { - m_data = data; - m_bitLength = dataLength * 8; + m_incomingMessageType = tp; } internal void Reset() { - m_bitLength = 0; + m_incomingMessageType = NetIncomingMessageType.Error; m_readPosition = 0; - m_status = NetIncomingMessageReleaseStatus.NotReleased; - m_fragmentationInfo = null; + m_receivedMessageType = NetMessageType.LibraryError; + m_senderConnection = null; + m_bitLength = 0; + m_isFragment = false; } public void Decrypt(NetXtea tea) @@ -130,34 +111,9 @@ namespace Lidgren.Network m_data = result; } - public NetIncomingMessage Clone() - { - NetIncomingMessage retval = new NetIncomingMessage(); - - // copy content - retval.m_data = new byte[LengthBytes]; - Buffer.BlockCopy(m_data, 0, retval.m_data, 0, LengthBytes); - - retval.m_bitLength = m_bitLength; - retval.m_messageType = m_messageType; - retval.m_sequenceNumber = m_sequenceNumber; - retval.m_status = m_status; - retval.m_incomingType = m_incomingType; - retval.m_senderEndpoint = m_senderEndpoint; - retval.m_senderConnection = m_senderConnection; - retval.m_fragmentationInfo = m_fragmentationInfo; - - return retval; - } - public override string ToString() { - return String.Format("[NetIncomingMessage {0}, {1}|{2}, {3} bits]", - m_incomingType, - m_messageType, - m_sequenceNumber, - m_bitLength - ); + return "[NetIncomingMessage #" + m_sequenceNumber + " " + this.LengthBytes + " bytes]"; } } } diff --git a/Lidgren.Network/NetIncomingMessageType.cs b/Lidgren.Network/NetIncomingMessageType.cs index 043832b..99d0cc5 100644 --- a/Lidgren.Network/NetIncomingMessageType.cs +++ b/Lidgren.Network/NetIncomingMessageType.cs @@ -23,7 +23,7 @@ using System.Diagnostics.CodeAnalysis; namespace Lidgren.Network { /// - /// Type of incoming message + /// The type of a NetIncomingMessage /// [SuppressMessage("Microsoft.Design", "CA1027:MarkEnumsWithFlags")] public enum NetIncomingMessageType diff --git a/Lidgren.Network/NetMessageType.cs b/Lidgren.Network/NetMessageType.cs index 506ea0c..b05aecb 100644 --- a/Lidgren.Network/NetMessageType.cs +++ b/Lidgren.Network/NetMessageType.cs @@ -20,148 +20,175 @@ using System; namespace Lidgren.Network { - // publicly visible subset of NetMessageType - - /// - /// How the library deals with dropped and delayed messages - /// - public enum NetDeliveryMethod : byte - { - Unknown = 0, - Unreliable = 2, - UnreliableSequenced = 3, - ReliableUnordered = 35, - ReliableSequenced = 36, - ReliableOrdered = 68, - } - - internal enum NetMessageLibraryType : byte - { - Error = 0, - KeepAlive = 1, // used for piggybacking acks - Ping = 2, // used for RTT calculation - Pong = 3, // used for RTT calculation - Connect = 4, - ConnectResponse = 5, - ConnectionEstablished = 6, - Acknowledge = 7, - Disconnect = 8, - Discovery = 9, - DiscoveryResponse = 10, - NatPunchMessage = 11, // send between peers - NatIntroduction = 12, // send to master server - } - internal enum NetMessageType : byte { - Error = 0, + Unconnected = 0, - Library = 1, // NetMessageLibraryType byte follows + UserUnreliable = 1, - UserUnreliable = 2, + UserSequenced1 = 2, + UserSequenced2 = 3, + UserSequenced3 = 4, + UserSequenced4 = 5, + UserSequenced5 = 6, + UserSequenced6 = 7, + UserSequenced7 = 8, + UserSequenced8 = 9, + UserSequenced9 = 10, + UserSequenced10 = 11, + UserSequenced11 = 12, + UserSequenced12 = 13, + UserSequenced13 = 14, + UserSequenced14 = 15, + UserSequenced15 = 16, + UserSequenced16 = 17, + UserSequenced17 = 18, + UserSequenced18 = 19, + UserSequenced19 = 20, + UserSequenced20 = 21, + UserSequenced21 = 22, + UserSequenced22 = 23, + UserSequenced23 = 24, + UserSequenced24 = 25, + UserSequenced25 = 26, + UserSequenced26 = 27, + UserSequenced27 = 28, + UserSequenced28 = 29, + UserSequenced29 = 30, + UserSequenced30 = 31, + UserSequenced31 = 32, + UserSequenced32 = 33, - // 3 to 34 = UserSequenced 0 to 31 - UserSequenced = 3, - UserSequenced1 = 4, - UserSequenced2 = 5, - UserSequenced3 = 6, - UserSequenced4 = 7, - UserSequenced5 = 8, - UserSequenced6 = 9, - UserSequenced7 = 10, - UserSequenced8 = 11, - UserSequenced9 = 12, - UserSequenced10 = 13, - UserSequenced11 = 14, - UserSequenced12 = 15, - UserSequenced13 = 16, - UserSequenced14 = 17, - UserSequenced15 = 18, - UserSequenced16 = 19, - UserSequenced17 = 20, - UserSequenced18 = 21, - UserSequenced19 = 22, - UserSequenced20 = 23, - UserSequenced21 = 24, - UserSequenced22 = 25, - UserSequenced23 = 26, - UserSequenced24 = 27, - UserSequenced25 = 28, - UserSequenced26 = 29, - UserSequenced27 = 30, - UserSequenced28 = 31, - UserSequenced29 = 32, - UserSequenced30 = 33, - UserSequenced31 = 34, + UserReliableUnordered = 34, - UserReliableUnordered = 35, + UserReliableSequenced1 = 35, + UserReliableSequenced2 = 36, + UserReliableSequenced3 = 37, + UserReliableSequenced4 = 38, + UserReliableSequenced5 = 39, + UserReliableSequenced6 = 40, + UserReliableSequenced7 = 41, + UserReliableSequenced8 = 42, + UserReliableSequenced9 = 43, + UserReliableSequenced10 = 44, + UserReliableSequenced11 = 45, + UserReliableSequenced12 = 46, + UserReliableSequenced13 = 47, + UserReliableSequenced14 = 48, + UserReliableSequenced15 = 49, + UserReliableSequenced16 = 50, + UserReliableSequenced17 = 51, + UserReliableSequenced18 = 52, + UserReliableSequenced19 = 53, + UserReliableSequenced20 = 54, + UserReliableSequenced21 = 55, + UserReliableSequenced22 = 56, + UserReliableSequenced23 = 57, + UserReliableSequenced24 = 58, + UserReliableSequenced25 = 59, + UserReliableSequenced26 = 60, + UserReliableSequenced27 = 61, + UserReliableSequenced28 = 62, + UserReliableSequenced29 = 63, + UserReliableSequenced30 = 64, + UserReliableSequenced31 = 65, + UserReliableSequenced32 = 66, - // 36 to 67 = UserReliableSequenced 0 to 31 - UserReliableSequenced = 36, - UserReliableSequenced1 = 37, - UserReliableSequenced2 = 38, - UserReliableSequenced3 = 39, - UserReliableSequenced4 = 40, - UserReliableSequenced5 = 41, - UserReliableSequenced6 = 42, - UserReliableSequenced7 = 43, - UserReliableSequenced8 = 44, - UserReliableSequenced9 = 45, - UserReliableSequenced10 = 46, - UserReliableSequenced11 = 47, - UserReliableSequenced12 = 48, - UserReliableSequenced13 = 49, - UserReliableSequenced14 = 50, - UserReliableSequenced15 = 51, - UserReliableSequenced16 = 52, - UserReliableSequenced17 = 53, - UserReliableSequenced18 = 54, - UserReliableSequenced19 = 55, - UserReliableSequenced20 = 56, - UserReliableSequenced21 = 57, - UserReliableSequenced22 = 58, - UserReliableSequenced23 = 59, - UserReliableSequenced24 = 60, - UserReliableSequenced25 = 61, - UserReliableSequenced26 = 62, - UserReliableSequenced27 = 63, - UserReliableSequenced28 = 64, - UserReliableSequenced29 = 65, - UserReliableSequenced30 = 66, - UserReliableSequenced31 = 67, + UserReliableOrdered1 = 67, + UserReliableOrdered2 = 68, + UserReliableOrdered3 = 69, + UserReliableOrdered4 = 70, + UserReliableOrdered5 = 71, + UserReliableOrdered6 = 72, + UserReliableOrdered7 = 73, + UserReliableOrdered8 = 74, + UserReliableOrdered9 = 75, + UserReliableOrdered10 = 76, + UserReliableOrdered11 = 77, + UserReliableOrdered12 = 78, + UserReliableOrdered13 = 79, + UserReliableOrdered14 = 80, + UserReliableOrdered15 = 81, + UserReliableOrdered16 = 82, + UserReliableOrdered17 = 83, + UserReliableOrdered18 = 84, + UserReliableOrdered19 = 85, + UserReliableOrdered20 = 86, + UserReliableOrdered21 = 87, + UserReliableOrdered22 = 88, + UserReliableOrdered23 = 89, + UserReliableOrdered24 = 90, + UserReliableOrdered25 = 91, + UserReliableOrdered26 = 92, + UserReliableOrdered27 = 93, + UserReliableOrdered28 = 94, + UserReliableOrdered29 = 95, + UserReliableOrdered30 = 96, + UserReliableOrdered31 = 97, + UserReliableOrdered32 = 98, - // 68 to 99 = UserReliableOrdered 0 to 31 - UserReliableOrdered = 68, - UserReliableOrdered1 = 69, - UserReliableOrdered2 = 70, - UserReliableOrdered3 = 71, - UserReliableOrdered4 = 72, - UserReliableOrdered5 = 73, - UserReliableOrdered6 = 74, - UserReliableOrdered7 = 75, - UserReliableOrdered8 = 76, - UserReliableOrdered9 = 77, - UserReliableOrdered10 = 78, - UserReliableOrdered11 = 79, - UserReliableOrdered12 = 80, - UserReliableOrdered13 = 81, - UserReliableOrdered14 = 82, - UserReliableOrdered15 = 83, - UserReliableOrdered16 = 84, - UserReliableOrdered17 = 85, - UserReliableOrdered18 = 86, - UserReliableOrdered19 = 87, - UserReliableOrdered20 = 88, - UserReliableOrdered21 = 89, - UserReliableOrdered22 = 90, - UserReliableOrdered23 = 91, - UserReliableOrdered24 = 92, - UserReliableOrdered25 = 93, - UserReliableOrdered26 = 94, - UserReliableOrdered27 = 95, - UserReliableOrdered28 = 96, - UserReliableOrdered29 = 97, - UserReliableOrdered30 = 98, - UserReliableOrdered31 = 99, + Unused1 = 99, + Unused2 = 100, + Unused3 = 101, + Unused4 = 102, + Unused5 = 103, + Unused6 = 104, + Unused7 = 105, + Unused8 = 106, + Unused9 = 107, + Unused10 = 108, + Unused11 = 109, + Unused12 = 110, + Unused13 = 111, + Unused14 = 112, + Unused15 = 113, + Unused16 = 114, + Unused17 = 115, + Unused18 = 116, + Unused19 = 117, + Unused20 = 118, + Unused21 = 119, + Unused22 = 120, + Unused23 = 121, + Unused24 = 122, + Unused25 = 123, + Unused26 = 124, + Unused27 = 125, + Unused28 = 126, + Unused29 = 127, + + LibraryError = 128, + Ping = 129, // used for RTT calculation + Pong = 130, // used for RTT calculation + Connect = 131, + ConnectResponse = 132, + ConnectionEstablished = 133, + Acknowledge = 134, + Disconnect = 135, + Discovery = 136, + DiscoveryResponse = 137, + NatPunchMessage = 138, // send between peers + NatIntroduction = 139, // send to master server + } + + internal static class NetMessageTypeExtensions + { + internal static bool IsLibrary(this NetMessageType tp) + { + return tp >= NetMessageType.LibraryError; + } + + internal static NetDeliveryMethod GetDeliveryMethod(this NetMessageType mtp) + { + if (mtp >= NetMessageType.UserReliableOrdered1) + return NetDeliveryMethod.ReliableOrdered; + else if (mtp >= NetMessageType.UserReliableSequenced1) + return NetDeliveryMethod.ReliableSequenced; + else if (mtp >= NetMessageType.UserReliableUnordered) + return NetDeliveryMethod.ReliableUnordered; + else if (mtp >= NetMessageType.UserSequenced1) + return NetDeliveryMethod.UnreliableSequenced; + return NetDeliveryMethod.Unreliable; + } } } \ No newline at end of file diff --git a/Lidgren.Network/NetNatIntroduction.cs b/Lidgren.Network/NetNatIntroduction.cs index 40ef758..7d1ff75 100644 --- a/Lidgren.Network/NetNatIntroduction.cs +++ b/Lidgren.Network/NetNatIntroduction.cs @@ -18,23 +18,23 @@ namespace Lidgren.Network { // send message to client NetOutgoingMessage msg = CreateMessage(10 + token.Length + 1); - msg.m_libType = NetMessageLibraryType.NatIntroduction; + msg.m_messageType = NetMessageType.NatIntroduction; msg.Write(false); msg.WritePadBits(); msg.Write(hostInternal); msg.Write(hostExternal); msg.Write(token); - SendUnconnectedLibrary(msg, clientExternal); + m_unsentUnconnectedMessages.Enqueue(new NetTuple(clientExternal, msg)); // send message to host msg = CreateMessage(10 + token.Length + 1); - msg.m_libType = NetMessageLibraryType.NatIntroduction; + msg.m_messageType = NetMessageType.NatIntroduction; msg.Write(true); msg.WritePadBits(); msg.Write(clientInternal); msg.Write(clientExternal); msg.Write(token); - SendUnconnectedLibrary(msg, hostExternal); + m_unsentUnconnectedMessages.Enqueue(new NetTuple(hostExternal, msg)); } /// @@ -45,8 +45,8 @@ namespace Lidgren.Network VerifyNetworkThread(); // read intro - NetIncomingMessage tmp = new NetIncomingMessage(m_receiveBuffer, 1000); // never mind length - tmp.Position = (ptr * 8); + NetIncomingMessage tmp = SetupReadHelperMessage(ptr, 1000); // never mind length + byte hostByte = tmp.ReadByte(); IPEndPoint remoteInternal = tmp.ReadIPEndpoint(); IPEndPoint remoteExternal = tmp.ReadIPEndpoint(); @@ -62,17 +62,17 @@ namespace Lidgren.Network // send internal punch punch = CreateMessage(1); - punch.m_libType = NetMessageLibraryType.NatPunchMessage; + punch.m_messageType = NetMessageType.NatPunchMessage; punch.Write(hostByte); punch.Write(token); - SendUnconnectedLibrary(punch, remoteInternal); + m_unsentUnconnectedMessages.Enqueue(new NetTuple(remoteInternal, punch)); // send external punch punch = CreateMessage(1); - punch.m_libType = NetMessageLibraryType.NatPunchMessage; + punch.m_messageType = NetMessageType.NatPunchMessage; punch.Write(hostByte); punch.Write(token); - SendUnconnectedLibrary(punch, remoteExternal); + m_unsentUnconnectedMessages.Enqueue(new NetTuple(remoteExternal, punch)); } /// @@ -80,8 +80,7 @@ namespace Lidgren.Network /// private void HandleNatPunch(int ptr, IPEndPoint senderEndpoint) { - NetIncomingMessage tmp = new NetIncomingMessage(m_receiveBuffer, 1000); // never mind length - tmp.Position = (ptr * 8); + NetIncomingMessage tmp = SetupReadHelperMessage(ptr, 1000); // never mind length byte fromHostByte = tmp.ReadByte(); if (fromHostByte == 0) diff --git a/Lidgren.Network/NetOutgoingMessage.Stream.cs b/Lidgren.Network/NetOutgoingMessage.Stream.cs deleted file mode 100644 index d7fc94b..0000000 --- a/Lidgren.Network/NetOutgoingMessage.Stream.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.IO; - -namespace Lidgren.Network -{ - public partial class NetOutgoingMessage : Stream - { - public override bool CanRead { get { return false; } } - public override bool CanSeek { get { return false; } } - public override bool CanWrite { get { return true; } } - - public override void Flush() - { - // no op - } - - /// - /// Gets the length of the stream, in bytes - /// - public override long Length - { - get { return (long)LengthBytes; } - } - - public override long Position - { - get - { - throw new NetException("Position in bytes is not relevant since the bit count can vary"); - } - set - { - throw new NetException("It's not possible to seek in this message"); - } - } - - public override int Read(byte[] buffer, int offset, int count) - { - throw new NetException("It's not possible to read from this message"); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NetException("It's not possible to seek in this message"); - } - - public override void SetLength(long value) - { - throw new NetException("It's not possible to set the length of this message"); - } - } -} diff --git a/Lidgren.Network/NetOutgoingMessage.Write.Reflection.cs b/Lidgren.Network/NetOutgoingMessage.Write.Reflection.cs index 252a2c1..a05e6b3 100644 --- a/Lidgren.Network/NetOutgoingMessage.Write.Reflection.cs +++ b/Lidgren.Network/NetOutgoingMessage.Write.Reflection.cs @@ -41,7 +41,7 @@ namespace Lidgren.Network Type tp = ob.GetType(); FieldInfo[] fields = tp.GetFields(flags); - NetIncomingMessage.SortMembersList(fields); + NetUtility.SortMembersList(fields); foreach (FieldInfo fi in fields) { @@ -74,7 +74,7 @@ namespace Lidgren.Network Type tp = ob.GetType(); PropertyInfo[] fields = tp.GetProperties(flags); - NetIncomingMessage.SortMembersList(fields); + NetUtility.SortMembersList(fields); foreach (PropertyInfo fi in fields) { diff --git a/Lidgren.Network/NetOutgoingMessage.Write.cs b/Lidgren.Network/NetOutgoingMessage.Write.cs index 6a4dea8..07a1711 100644 --- a/Lidgren.Network/NetOutgoingMessage.Write.cs +++ b/Lidgren.Network/NetOutgoingMessage.Write.cs @@ -160,7 +160,7 @@ namespace Lidgren.Network m_bitLength += bits; } - public override void Write(byte[] source, int offsetInBytes, int numberOfBytes) + public void Write(byte[] source, int offsetInBytes, int numberOfBytes) { if (source == null) throw new ArgumentNullException("source"); diff --git a/Lidgren.Network/NetOutgoingMessage.cs b/Lidgren.Network/NetOutgoingMessage.cs index 7f04126..6d42e5c 100644 --- a/Lidgren.Network/NetOutgoingMessage.cs +++ b/Lidgren.Network/NetOutgoingMessage.cs @@ -15,182 +15,103 @@ PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Net; -using System.Text; namespace Lidgren.Network { + /// + /// Outgoing message used to send data to remote peer(s) + /// [DebuggerDisplay("LengthBits={LengthBits}")] public sealed partial class NetOutgoingMessage { - // reference count before message can be recycled - internal int m_numUnfinishedSendings; + internal NetMessageType m_messageType; + internal bool m_isSent; + internal int m_recyclingCount; - internal bool m_wasSent; // true is SendMessage() public method has been called - internal NetMessageLibraryType m_libType = NetMessageLibraryType.Error; - - //internal int m_fragmentGroupId; - //internal int m_fragmentNumber; - //internal int m_fragmentTotalCount; - - /// - /// Returns true if this message has been passed to SendMessage() already - /// - public bool IsSent { get { return m_wasSent; } } + internal int m_fragmentGroup; // which group of fragments ths belongs to + internal int m_fragmentGroupTotalBits; // total number of bits in this group + internal int m_fragmentChunkByteSize; // size, in bytes, of every chunk but the last one + internal int m_fragmentChunkNumber; // which number chunk this is, starting with 0 internal NetOutgoingMessage() { } - internal void Reset() + public void Reset() { - NetException.Assert(m_numUnfinishedSendings == 0, "Ouch! Resetting NetOutgoingMessage still in some queue!"); - NetException.Assert(m_wasSent == true, "Ouch! Resetting unsent message!"); - + m_messageType = NetMessageType.LibraryError; m_bitLength = 0; - m_libType = NetMessageLibraryType.Error; - m_wasSent = false; + m_isSent = false; + m_recyclingCount = 0; + m_fragmentGroup = 0; } - internal static int EncodeAcksMessage(byte[] buffer, int ptr, NetConnection conn, int maxBytesPayload) + internal int Encode(byte[] intoBuffer, int ptr, int sequenceNumber) { - // TODO: if appropriate; make bit vector of adjacent acks + // 8 bits - NetMessageType + // 1 bit - Fragment? + // 15 bits - Sequence number + // 16 bits - Payload length in bits + + intoBuffer[ptr++] = (byte)m_messageType; - buffer[ptr++] = (byte)NetMessageType.Library; - buffer[ptr++] = (byte)NetMessageLibraryType.Acknowledge; + byte low = (byte)((sequenceNumber << 1) | (m_fragmentGroup == 0 ? 0 : 1)); + intoBuffer[ptr++] = low; + intoBuffer[ptr++] = (byte)(sequenceNumber >> 7); - Queue acks = conn.m_acknowledgesToSend; - - int maxAcks = maxBytesPayload / 3; - int acksToEncode = (acks.Count < maxAcks ? acks.Count : maxAcks); - - int payloadBitsLength = acksToEncode * 3 * 8; - if (payloadBitsLength < 127) + if (m_fragmentGroup == 0) { - buffer[ptr++] = (byte)payloadBitsLength; + intoBuffer[ptr++] = (byte)m_bitLength; + intoBuffer[ptr++] = (byte)(m_bitLength >> 8); + + int byteLen = NetUtility.BytesToHoldBits(m_bitLength); + if (byteLen > 0) + { + Buffer.BlockCopy(m_data, 0, intoBuffer, ptr, byteLen); + ptr += byteLen; + } } else { - buffer[ptr++] = (byte)((payloadBitsLength & 127) | 128); - buffer[ptr++] = (byte)(payloadBitsLength >> 7); - } - - for (int i = 0; i < acksToEncode; i++) - { - int ack = acks.Dequeue(); - buffer[ptr++] = (byte)ack; // message type - buffer[ptr++] = (byte)(ack >> 8); // seqnr low - buffer[ptr++] = (byte)(ack >> 16); // seqnr high + int wasPtr = ptr; + intoBuffer[ptr++] = (byte)m_bitLength; + intoBuffer[ptr++] = (byte)(m_bitLength >> 8); + + // + // write fragmentation header + // + ptr = NetFragmentationHelper.WriteHeader(intoBuffer, ptr, m_fragmentGroup, m_fragmentGroupTotalBits, m_fragmentChunkByteSize, m_fragmentChunkNumber); + int hdrLen = ptr - wasPtr - 2; + + // update length + int realBitLength = m_bitLength + (hdrLen * 8); + intoBuffer[wasPtr] = (byte)realBitLength; + intoBuffer[wasPtr + 1] = (byte)(realBitLength >> 8); + + int byteLen = NetUtility.BytesToHoldBits(m_bitLength); + if (byteLen > 0) + { + Buffer.BlockCopy(m_data, (int)(m_fragmentChunkNumber * m_fragmentChunkByteSize), intoBuffer, ptr, byteLen); + ptr += byteLen; + } } + NetException.Assert(ptr > 0); return ptr; } - internal int EncodeUnfragmented(byte[] buffer, int ptr, NetMessageType tp, ushort sequenceNumber) + internal int GetEncodedSize() { - // message type - buffer[ptr++] = (byte)tp; // | (m_fragmentGroupId == -1 ? 0 : 128)); + int retval = 5; // regular headers + if (m_fragmentGroup != 0) + retval += NetFragmentationHelper.GetFragmentationHeaderSize(m_fragmentGroup, m_fragmentGroupTotalBits / 8, m_fragmentChunkByteSize, m_fragmentChunkNumber); + retval += this.LengthBytes; - if (tp == NetMessageType.Library) - buffer[ptr++] = (byte)m_libType; - - // channel sequence number - if (tp >= NetMessageType.UserSequenced) - { - ushort seqNr = (ushort)sequenceNumber; - buffer[ptr++] = (byte)seqNr; - buffer[ptr++] = (byte)(seqNr >> 8); - } - - // payload length - int payloadBitsLength = LengthBits; - int payloadBytesLength = NetUtility.BytesToHoldBits(payloadBitsLength); - if (payloadBitsLength < 127) - { - buffer[ptr++] = (byte)payloadBitsLength; - } - else if (payloadBitsLength < 32768) - { - buffer[ptr++] = (byte)((payloadBitsLength & 127) | 128); - buffer[ptr++] = (byte)(payloadBitsLength >> 7); - } - else - { - throw new NetException("Packet content too large; 4095 bytes maximum"); - } - - // payload - if (payloadBitsLength > 0) - { - // zero out last byte - buffer[ptr + payloadBytesLength] = 0; - - Buffer.BlockCopy(m_data, 0, buffer, ptr, payloadBytesLength); - ptr += payloadBytesLength; - } - - return ptr; - } - - internal int EncodeFragmented(byte[] buffer, int ptr, NetSending send, int mtu) - { - NetException.Assert(send.MessageType != NetMessageType.Library, "Library messages cant be fragmented"); - - // message type - buffer[ptr++] = (byte)((int)send.MessageType | 128); - - // channel sequence number - if (send.MessageType >= NetMessageType.UserSequenced) - { - ushort seqNr = (ushort)send.SequenceNumber; - buffer[ptr++] = (byte)seqNr; - buffer[ptr++] = (byte)(seqNr >> 8); - } - - // calculate fragment payload length - mtu -= NetConstants.FragmentHeaderSize; // size of fragmentation info - int thisFragmentLength = (send.FragmentNumber == send.FragmentTotalCount - 1 ? (send.Message.LengthBytes - (mtu * (send.FragmentTotalCount - 1))) : mtu); - - int payloadBitsLength = thisFragmentLength * 8; - if (payloadBitsLength < 127) - { - buffer[ptr++] = (byte)payloadBitsLength; - } - else if (payloadBitsLength < 32768) - { - buffer[ptr++] = (byte)((payloadBitsLength & 127) | 128); - buffer[ptr++] = (byte)(payloadBitsLength >> 7); - } - else - { - throw new NetException("Packet content too large; 4095 bytes maximum"); - } - - // fragmentation info - buffer[ptr++] = (byte)send.FragmentGroupId; - buffer[ptr++] = (byte)(send.FragmentGroupId >> 8); - buffer[ptr++] = (byte)send.FragmentTotalCount; - buffer[ptr++] = (byte)(send.FragmentTotalCount >> 8); - buffer[ptr++] = (byte)send.FragmentNumber; - buffer[ptr++] = (byte)(send.FragmentNumber >> 8); - - // payload - if (payloadBitsLength > 0) - { - // zero out last byte - buffer[ptr + thisFragmentLength] = 0; - - int offset = (mtu * send.FragmentNumber); - - Buffer.BlockCopy(m_data, offset, buffer, ptr, thisFragmentLength); - ptr += thisFragmentLength; - } - - return ptr; + return retval; } public void Encrypt(NetXtea tea) @@ -204,14 +125,14 @@ namespace Lidgren.Network Write((byte)0); byte[] result = new byte[m_data.Length]; - for(int i=0;i(new IPEndPoint(IPAddress.Broadcast, serverPort), om)); } /// @@ -23,18 +23,35 @@ namespace Lidgren.Network IPAddress address = NetUtility.Resolve(host); if (address == null) return false; - return DiscoverKnownPeer(new IPEndPoint(address, serverPort)); + DiscoverKnownPeer(new IPEndPoint(address, serverPort)); + return true; } /// /// Emit a discovery signal to a single known host /// - public bool DiscoverKnownPeer(IPEndPoint endpoint) + public void DiscoverKnownPeer(IPEndPoint endpoint) { NetOutgoingMessage om = CreateMessage(0); - om.m_libType = NetMessageLibraryType.Discovery; - SendUnconnectedLibrary(om, endpoint); - return true; + om.m_messageType = NetMessageType.Discovery; + m_unsentUnconnectedMessages.Enqueue(new NetTuple(endpoint, om)); + } + + /// + /// Send a discovery response message + /// + public void SendDiscoveryResponse(NetOutgoingMessage msg, IPEndPoint recipient) + { + if (recipient == null) + throw new ArgumentNullException("recipient"); + + if (msg == null) + msg = CreateMessage(0); + else if (msg.m_isSent) + throw new NetException("Message has already been sent!"); + + msg.m_messageType = NetMessageType.DiscoveryResponse; + m_unsentUnconnectedMessages.Enqueue(new NetTuple(recipient, msg)); } } } diff --git a/Lidgren.Network/NetPeer.Fragmentation.cs b/Lidgren.Network/NetPeer.Fragmentation.cs new file mode 100644 index 0000000..e039c82 --- /dev/null +++ b/Lidgren.Network/NetPeer.Fragmentation.cs @@ -0,0 +1,150 @@ +using System; +using System.Threading; +using System.Collections.Generic; + +namespace Lidgren.Network +{ + internal class ReceivedFragmentGroup + { + public float LastReceived; + public byte[] Data; + public NetBitVector ReceivedChunks; + } + + public partial class NetPeer + { + private int m_lastUsedFragmentGroup; + + private Dictionary m_receivedFragmentGroups; + + // on user thread + private void SendFragmentedMessage(NetOutgoingMessage msg, IList recipients, NetDeliveryMethod method, int sequenceChannel) + { + int group = Interlocked.Increment(ref m_lastUsedFragmentGroup); + if (group >= NetConstants.MaxFragmentationGroups) + { + // TODO: not thread safe; but in practice probably not an issue + m_lastUsedFragmentGroup = 1; + group = 1; + } + msg.m_fragmentGroup = group; + + // do not send msg; but set fragmentgroup in case user tries to recycle it immediately + + // create fragmentation specifics + int totalBytes = msg.LengthBytes; + int mtu = m_configuration.MaximumTransmissionUnit; + + int bytesPerChunk = NetFragmentationHelper.GetBestChunkSize(group, totalBytes, mtu); + + int numChunks = totalBytes / bytesPerChunk; + if (numChunks * bytesPerChunk < totalBytes) + numChunks++; + + int bitsPerChunk = bytesPerChunk * 8; + int bitsLeft = msg.LengthBits; + for (int i = 0; i < numChunks; i++) + { + NetOutgoingMessage chunk = CreateMessage(mtu); + + chunk.m_bitLength = (bitsLeft > bitsPerChunk ? bitsPerChunk : bitsLeft); + chunk.m_data = msg.m_data; + chunk.m_fragmentGroup = group; + chunk.m_fragmentGroupTotalBits = totalBytes * 8; + chunk.m_fragmentChunkByteSize = bytesPerChunk; + chunk.m_fragmentChunkNumber = i; + + NetException.Assert(chunk.m_bitLength != 0); + NetException.Assert(chunk.GetEncodedSize() < mtu); + + Interlocked.Add(ref chunk.m_recyclingCount, recipients.Count); + + foreach (NetConnection recipient in recipients) + recipient.EnqueueMessage(chunk, method, sequenceChannel); + + bitsLeft -= bitsPerChunk; + } + + return; + } + + + + private void HandleReleasedFragment(NetIncomingMessage im) + { + // + // read fragmentation header and combine fragments + // + int group; + int totalBits; + int chunkByteSize; + int chunkNumber; + int ptr = NetFragmentationHelper.ReadHeader( + im.m_data, 0, + out group, + out totalBits, + out chunkByteSize, + out chunkNumber + ); + + NetException.Assert(im.LengthBytes > ptr); + + NetException.Assert(group > 0); + NetException.Assert(totalBits > 0); + NetException.Assert(chunkByteSize > 0); + + int totalBytes = NetUtility.BytesToHoldBits((int)totalBits); + int totalNumChunks = totalBytes / chunkByteSize; + if (totalNumChunks * chunkByteSize < totalBytes) + totalNumChunks++; + + NetException.Assert(chunkNumber < totalNumChunks); + + if (chunkNumber >= totalNumChunks) + { + LogWarning("Index out of bounds for chunk " + chunkNumber + " (total chunks " + totalNumChunks + ")"); + return; + } + + ReceivedFragmentGroup info; + if (!m_receivedFragmentGroups.TryGetValue(group, out info)) + { + info = new ReceivedFragmentGroup(); + info.Data = new byte[totalBytes]; + info.ReceivedChunks = new NetBitVector(totalNumChunks); + m_receivedFragmentGroups[group] = info; + } + + info.ReceivedChunks[chunkNumber] = true; + info.LastReceived = (float)NetTime.Now; + + // copy to data + int offset = (chunkNumber * chunkByteSize); + 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("Received fragment " + chunkNumber + " of " + totalNumChunks + " (" + cnt + " chunks received)"); + + if (info.ReceivedChunks.Count() == totalNumChunks) + { + // Done! Transform this incoming message + im.m_data = info.Data; + im.m_bitLength = (int)totalBits; + im.m_isFragment = false; + + LogVerbose("Fragment group #" + group + " fully received in " + totalNumChunks + " chunks (" + totalBits + " bits)"); + + ReleaseMessage(im); + } + else + { + // data has been copied; recycle this incoming message + Recycle(im); + } + + return; + } + } +} diff --git a/Lidgren.Network/NetPeer.Internal.cs b/Lidgren.Network/NetPeer.Internal.cs index a4f3f71..605a4b4 100644 --- a/Lidgren.Network/NetPeer.Internal.cs +++ b/Lidgren.Network/NetPeer.Internal.cs @@ -1,105 +1,66 @@ -/* Copyright (c) 2010 Michael Lidgren - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software -and associated documentation files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom -the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ -#define IS_MAC_AVAILABLE +#define IS_MAC_AVAILABLE using System; using System.Net; -using System.Net.Sockets; using System.Threading; +using System.Diagnostics; +using System.Security.Cryptography; +using System.Net.Sockets; +using System.Collections.Generic; namespace Lidgren.Network { public partial class NetPeer { - private EndPoint m_senderRemote; - internal byte[] m_receiveBuffer; + private NetPeerStatus m_status; + private Thread m_networkThread; + private Socket m_socket; internal byte[] m_sendBuffer; - internal Socket m_socket; - internal byte[] m_macAddressBytes; - private int m_listenPort; + internal byte[] m_receiveBuffer; + internal NetIncomingMessage m_readHelperMessage; + private EndPoint m_senderRemote; + private object m_initializeLock = new object(); + + internal readonly NetPeerConfiguration m_configuration; + private readonly NetQueue m_releasedIncomingMessages; + internal readonly NetQueue> m_unsentUnconnectedMessages; + + internal Dictionary m_handshakes; + + internal readonly NetPeerStatistics m_statistics; + internal long m_uniqueIdentifier; + private AutoResetEvent m_messageReceivedEvent = new AutoResetEvent(false); - private readonly NetQueue m_releasedIncomingMessages = new NetQueue(8); - private readonly NetQueue m_unsentUnconnectedMessage = new NetQueue(2); - - /// - /// Signalling event which can be waited on to determine when a message is queued for reading. - /// Note that there is no guarantee that after the event is signaled the blocked thread will - /// find the message in the queue. Other user created threads could be preempted and dequeue - /// the message before the waiting thread wakes up. - /// - public AutoResetEvent MessageReceivedEvent { get { return m_messageReceivedEvent; } } - internal void ReleaseMessage(NetIncomingMessage msg) { - NetException.Assert(msg.m_status != NetIncomingMessageReleaseStatus.ReleasedToApplication, "Message released to application twice!"); + NetException.Assert(msg.m_incomingMessageType != NetIncomingMessageType.Error); - NetException.Assert(msg.m_fragmentationInfo == null, "Fragment released to application!"); - - msg.m_status = NetIncomingMessageReleaseStatus.ReleasedToApplication; + if (msg.m_isFragment) + { + HandleReleasedFragment(msg); + return; + } + m_releasedIncomingMessages.Enqueue(msg); if (m_messageReceivedEvent != null) m_messageReceivedEvent.Set(); } - [System.Diagnostics.Conditional("DEBUG")] - internal void VerifyNetworkThread() - { - Thread ct = System.Threading.Thread.CurrentThread; - if (ct != m_networkThread) - throw new NetException("Executing on wrong thread! Should be library system thread (is " + ct.Name + " mId " + ct.ManagedThreadId + ")"); - } - private void InitializeNetwork() { - // - // Initialize - // - - InitializeRecycling(); - - System.Net.NetworkInformation.PhysicalAddress pa = null; -#if IS_MAC_AVAILABLE - pa = NetUtility.GetMacAddress(); - if (pa != null) - { - m_macAddressBytes = pa.GetAddressBytes(); - LogVerbose("Mac address is " + NetUtility.ToHexString(m_macAddressBytes)); - } - else - { - LogWarning("Failed to get Mac address"); - } -#else - // random bytes is better than nothing - m_macAddressBytes = new byte[6]; - NetRandom.Instance.NextBytes(m_macAddressBytes); -#endif - LogDebug("Initializing Network"); - lock (m_initializeLock) { + m_configuration.Lock(); + if (m_status == NetPeerStatus.Running) return; - m_statistics.Reset(); + InitializePools(); + + m_releasedIncomingMessages.Clear(); + m_unsentUnconnectedMessages.Clear(); + m_handshakes.Clear(); // bind to socket IPEndPoint iep = null; @@ -115,36 +76,38 @@ namespace Lidgren.Network IPEndPoint boundEp = m_socket.LocalEndPoint as IPEndPoint; LogDebug("Socket bound to " + boundEp + ": " + m_socket.IsBound); - m_listenPort = boundEp.Port; - int first = (pa == null ? this.GetHashCode() : pa.GetHashCode()); - int second = boundEp.GetHashCode(); - - byte[] raw = new byte[8]; - raw[0] = (byte)first; - raw[1] = (byte)(first << 8); - raw[2] = (byte)(first << 16); - raw[3] = (byte)(first << 24); - raw[4] = (byte)second; - raw[5] = (byte)(second << 8); - raw[6] = (byte)(second << 16); - raw[7] = (byte)(second << 24); - m_uniqueIdentifier = BitConverter.ToInt64(NetSha.Hash(raw), 0); - m_receiveBuffer = new byte[m_configuration.ReceiveBufferSize]; m_sendBuffer = new byte[m_configuration.SendBufferSize]; + m_readHelperMessage = new NetIncomingMessage(NetIncomingMessageType.Error); + m_readHelperMessage.m_data = m_receiveBuffer; - LogVerbose("Initialization done"); + byte[] macBytes = new byte[8]; + NetRandom.Instance.NextBytes(macBytes); + +#if IS_MAC_AVAILABLE + System.Net.NetworkInformation.PhysicalAddress pa = NetUtility.GetMacAddress(); + if (pa != null) + { + macBytes = pa.GetAddressBytes(); + LogVerbose("Mac address is " + NetUtility.ToHexString(macBytes)); + } + else + { + LogWarning("Failed to get Mac address"); + } +#endif + byte[] epBytes = BitConverter.GetBytes(boundEp.GetHashCode()); + byte[] combined = new byte[epBytes.Length + macBytes.Length]; + Array.Copy(epBytes, 0, combined, 0, epBytes.Length); + Array.Copy(macBytes, 0, combined, epBytes.Length, macBytes.Length); + m_uniqueIdentifier = BitConverter.ToInt64(SHA1.Create().ComputeHash(combined), 0); - // only set Running if everything succeeds m_status = NetPeerStatus.Running; } } - // - // Network loop - // private void NetworkLoop() { VerifyNetworkThread(); @@ -169,14 +132,26 @@ namespace Lidgren.Network // // perform shutdown // + ExecutePeerShutdown(); + } + + private void ExecutePeerShutdown() + { + VerifyNetworkThread(); + LogDebug("Shutting down..."); // disconnect and make one final heartbeat lock (m_connections) { foreach (NetConnection conn in m_connections) - if (conn.m_status == NetConnectionStatus.Connected || conn.m_status == NetConnectionStatus.Connecting) - conn.Disconnect(m_shutdownReason); + conn.Shutdown(m_shutdownReason); + } + + lock (m_handshakes) + { + foreach (NetConnection conn in m_handshakes.Values) + conn.Shutdown(m_shutdownReason); } // one final heartbeat, will send stuff and do disconnect @@ -203,6 +178,12 @@ namespace Lidgren.Network m_status = NetPeerStatus.NotRunning; LogDebug("Shutdown complete"); } + + m_receiveBuffer = null; + m_sendBuffer = null; + m_unsentUnconnectedMessages.Clear(); + m_connections.Clear(); + m_handshakes.Clear(); } return; @@ -212,449 +193,300 @@ namespace Lidgren.Network { VerifyNetworkThread(); + float now = (float)NetTime.Now; + + // do handshake heartbeats + foreach (NetConnection conn in m_handshakes.Values) + { + conn.UnconnectedHeartbeat(now); + if (conn.m_status == NetConnectionStatus.Connected || conn.m_status == NetConnectionStatus.Disconnected) + break; // collection is modified + } + #if DEBUG - // send delayed packets SendDelayedPackets(); #endif - // connection approval - CheckPendingConnections(); - - double now = NetTime.Now; - // do connection heartbeats - foreach (NetConnection conn in m_connections) + lock (m_connections) { - conn.Heartbeat(now); - if (conn.m_status == NetConnectionStatus.Disconnected) + foreach (NetConnection conn in m_connections) { - RemoveConnection(conn); - break; // can't continue iteration here + conn.Heartbeat(now); + if (conn.m_status == NetConnectionStatus.Disconnected) + { + // + // remove connection + // + m_connections.Remove(conn); + m_connectionLookup.Remove(conn.RemoteEndpoint); + break; // can't continue iteration here + } } } - // send unconnected sends - NetSending uncSend; - while (m_unsentUnconnectedMessage.TryDequeue(out uncSend)) + // send unsent unconnected messages + NetTuple unsent; + while (m_unsentUnconnectedMessages.TryDequeue(out unsent)) { - // - // TODO: use throttling here - // + NetOutgoingMessage om = unsent.Item2; - int ptr = uncSend.Message.EncodeUnfragmented(m_sendBuffer, 0, uncSend.MessageType, uncSend.SequenceNumber); - bool connectionReset = false; + bool connReset; + int len = om.Encode(m_sendBuffer, 0, 0); + SendPacket(len, unsent.Item1, 1, out connReset); - if (uncSend.Recipient.Address.Equals(IPAddress.Broadcast)) - { - // send using broadcast - try - { - m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); - SendPacket(ptr, uncSend.Recipient, 1, out connectionReset); - } - finally - { - m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, false); - } - } - else - { - // send normally - SendPacket(ptr, uncSend.Recipient, 1, out connectionReset); - } - - if (connectionReset) - LogWarning(NetConstants.ConnResetMessage); - - int unfin = uncSend.Message.m_numUnfinishedSendings; - uncSend.Message.m_numUnfinishedSendings = unfin - 1; - if (unfin <= 1) - Recycle(uncSend.Message); + Interlocked.Decrement(ref om.m_recyclingCount); + if (om.m_recyclingCount <= 0) + Recycle(om); } - // check if we need to reduce the recycled pool - ReduceStoragePool(); - // // read from socket // - do + if (m_socket == null) + return; + + if (!m_socket.Poll(500, SelectMode.SelectRead)) // wait up to 1/2 ms for data to arrive + return; + + //if (m_socket == null || m_socket.Available < 1) + // return; + + int bytesReceived = 0; + try { - if (m_socket == null) + bytesReceived = m_socket.ReceiveFrom(m_receiveBuffer, 0, m_receiveBuffer.Length, SocketFlags.None, ref m_senderRemote); + } + catch (SocketException sx) + { + // no good response to this yet + if (sx.SocketErrorCode == SocketError.ConnectionReset) + { + // connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable" + // we should shut down the connection; but m_senderRemote seemingly cannot be trusted, so which connection should we shut down?! + //LogWarning("Connection reset by peer, seemingly from " + m_senderRemote); + lock (m_connections) + { + if (m_connections.Count + m_handshakes.Count == 1) + { + foreach (var kvp in m_handshakes) + kvp.Value.ExecuteDisconnect("Connection forcibly closed", true); + foreach (var conn in m_connections) + conn.ExecuteDisconnect("Connection forcibly closed", true); + } + } return; + } - if (!m_socket.Poll(1000, SelectMode.SelectRead)) // wait up to 1 ms for data to arrive + LogWarning(sx.ToString()); + return; + } + + if (bytesReceived < NetConstants.HeaderByteSize) + return; + + //LogVerbose("Received " + bytesReceived + " bytes"); + + IPEndPoint ipsender = (IPEndPoint)m_senderRemote; + + NetConnection sender = null; + m_connectionLookup.TryGetValue(ipsender, out sender); + + // + // parse packet into messages + // + int ptr = 0; + while ((bytesReceived - ptr) >= NetConstants.HeaderByteSize) + { + // decode header + // 8 bits - NetMessageType + // 1 bit - Fragment? + // 15 bits - Sequence number + // 16 bits - Payload length in bits + + NetMessageType tp = (NetMessageType)m_receiveBuffer[ptr++]; + + byte low = m_receiveBuffer[ptr++]; + byte high = m_receiveBuffer[ptr++]; + + bool isFragment = ((low & 1) == 1); + ushort sequenceNumber = (ushort)((low >> 1) | (((int)high) << 7)); + + ushort payloadBitLength = (ushort)(m_receiveBuffer[ptr++] | (m_receiveBuffer[ptr++] << 8)); + int payloadByteLength = NetUtility.BytesToHoldBits(payloadBitLength); + + if (bytesReceived - ptr < payloadByteLength) + { + LogWarning("Malformed packet; stated payload length " + payloadByteLength + ", remaining bytes " + (bytesReceived - ptr)); return; + } - //if (m_socket == null || m_socket.Available < 1) - // return; - - int bytesReceived = 0; try { - bytesReceived = m_socket.ReceiveFrom(m_receiveBuffer, 0, m_receiveBuffer.Length, SocketFlags.None, ref m_senderRemote); - } - catch (SocketException sx) - { - // no good response to this yet - if (sx.SocketErrorCode == SocketError.ConnectionReset) + NetException.Assert(tp < NetMessageType.Unused1 || tp > NetMessageType.Unused29); + + if (tp >= NetMessageType.LibraryError) { - // connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable" - // we should shut down the connection; but m_senderRemote seemingly cannot be trusted, so which connection should we shut down?! - //LogWarning("Connection reset by peer, seemingly from " + m_senderRemote); - lock (m_connections) + if (sender != null) + sender.ReceivedLibraryMessage(tp, ptr, payloadByteLength); + else + ReceivedUnconnectedLibraryMessage(ipsender, tp, ptr, payloadByteLength); + } + else + { + if (sender == null && !m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.UnconnectedData)) + return; // dropping unconnected message since it's not enabled + + NetIncomingMessage msg = CreateIncomingMessage(NetIncomingMessageType.Data, payloadByteLength); + msg.m_isFragment = isFragment; + msg.m_sequenceNumber = sequenceNumber; + msg.m_receivedMessageType = tp; + msg.m_senderConnection = sender; + msg.m_senderEndpoint = ipsender; + msg.m_bitLength = payloadBitLength; + Buffer.BlockCopy(m_receiveBuffer, ptr, msg.m_data, 0, payloadByteLength); + if (sender != null) { - if (m_connections.Count == 1) + if (tp == NetMessageType.Unconnected) { - // only one connection; let's shut it down, unless already in progress - m_connections[0].Disconnect("Connection forcibly closed"); - m_connections[0].ExecuteDisconnect(false); - m_connections[0].FinishDisconnect(); + // We're connected; but we can still send unconnected messages to this peer + msg.m_incomingMessageType = NetIncomingMessageType.UnconnectedData; + ReleaseMessage(msg); + } + else + { + // connected application (non-library) message + sender.ReceivedMessage(msg); } } - - return; - } - - LogWarning(sx.ToString()); - return; - } - - if (bytesReceived < NetPeer.kMinPacketHeaderSize) - return; - - // renew current time; we might have waited in Poll - now = NetTime.Now; - - //LogVerbose("Received " + bytesReceived + " bytes"); - - IPEndPoint ipsender = (IPEndPoint)m_senderRemote; - - NetConnection sender = null; - m_connectionLookup.TryGetValue(ipsender, out sender); - - int ptr = 0; - NetMessageType msgType; - NetMessageLibraryType libType = NetMessageLibraryType.Error; - - // - // parse packet into messages - // - int numMessagesReceived = 0; - while ((bytesReceived - ptr) >= NetPeer.kMinPacketHeaderSize) - { - // get NetMessageType - byte top = m_receiveBuffer[ptr++]; - bool isFragment = (top & 128) == 128; - msgType = (NetMessageType)(top & 127); - - // get NetmessageLibraryType? - if (msgType == NetMessageType.Library) - libType = (NetMessageLibraryType)m_receiveBuffer[ptr++]; - - // get sequence number? - ushort sequenceNumber; - if (msgType >= NetMessageType.UserSequenced) - sequenceNumber = (ushort)(m_receiveBuffer[ptr++] | (m_receiveBuffer[ptr++] << 8)); - else - sequenceNumber = 0; - - // get payload length - int payloadLengthBits = (int)m_receiveBuffer[ptr++]; - if ((payloadLengthBits & 128) == 128) // large payload - payloadLengthBits = (payloadLengthBits & 127) | (m_receiveBuffer[ptr++] << 7); - - int payloadLengthBytes = NetUtility.BytesToHoldBits(payloadLengthBits); - - if ((ptr + payloadLengthBytes) > bytesReceived) - { - LogWarning("Malformed message from " + ipsender.ToString() + "; not enough bytes"); - break; - } - - // - // handle incoming message - // - - if (msgType == NetMessageType.Error) - { - LogError("Malformed message; no message type!"); - continue; - } - - numMessagesReceived++; - - if (msgType == NetMessageType.Library) - { - if (sender == null) - HandleUnconnectedLibraryMessage(libType, ptr, payloadLengthBits, ipsender); - else - sender.HandleLibraryMessage(now, libType, ptr, payloadLengthBits); - } - else - { - if (sender == null) - { - if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.UnconnectedData)) - HandleUnconnectedUserMessage(ptr, payloadLengthBits, ipsender); - } else { - if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.Data)) - sender.HandleUserMessage(now, msgType, isFragment, sequenceNumber, ptr, payloadLengthBits); + // at this point we know the message type is enabled + // unconnected application (non-library) message + msg.m_incomingMessageType = NetIncomingMessageType.UnconnectedData; + ReleaseMessage(msg); } } - - if (isFragment) - ptr += NetConstants.FragmentHeaderSize; - - ptr += payloadLengthBytes; } - - m_statistics.PacketReceived(bytesReceived, numMessagesReceived); - - if (sender != null) + catch (Exception ex) { - sender.m_lastHeardFrom = now; - sender.m_statistics.PacketReceived(bytesReceived, numMessagesReceived); + LogError("Packet parsing error: " + ex.Message); } - - if (ptr < bytesReceived) - { - // malformed packet - LogWarning("Malformed packet from " + sender + " (" + ipsender + "); " + (ptr - bytesReceived) + " stray bytes"); - continue; - } - } while (true); + ptr += payloadByteLength; + } } - private void HandleUnconnectedLibraryMessage(NetMessageLibraryType libType, int ptr, int payloadLengthBits, IPEndPoint senderEndpoint) + private void ReceivedUnconnectedLibraryMessage(IPEndPoint senderEndpoint, NetMessageType tp, int ptr, int payloadByteLength) { - VerifyNetworkThread(); - - int payloadLengthBytes = NetUtility.BytesToHoldBits(payloadLengthBits); - - switch (libType) + NetConnection shake; + if (m_handshakes.TryGetValue(senderEndpoint, out shake)) { - case NetMessageLibraryType.NatPunchMessage: - HandleNatPunch(ptr, senderEndpoint); - break; - case NetMessageLibraryType.NatIntroduction: - HandleNatIntroduction(ptr); - break; - case NetMessageLibraryType.Discovery: + shake.ReceivedHandshake(tp, ptr, payloadByteLength); + return; + } + + // + // Library message from a completely unknown sender; lets just accept Connect + // + switch (tp) + { + case NetMessageType.Discovery: if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.DiscoveryRequest)) { - NetIncomingMessage dm = CreateIncomingMessage(NetIncomingMessageType.DiscoveryRequest, payloadLengthBytes); - if (payloadLengthBytes > 0) - Buffer.BlockCopy(m_receiveBuffer, ptr, dm.m_data, 0, payloadLengthBytes); - dm.m_bitLength = payloadLengthBits; + NetIncomingMessage dm = CreateIncomingMessage(NetIncomingMessageType.DiscoveryRequest, payloadByteLength); + if (payloadByteLength > 0) + Buffer.BlockCopy(m_receiveBuffer, ptr, dm.m_data, 0, payloadByteLength); + dm.m_bitLength = payloadByteLength * 8; dm.m_senderEndpoint = senderEndpoint; ReleaseMessage(dm); } + return; - break; - case NetMessageLibraryType.DiscoveryResponse: + case NetMessageType.DiscoveryResponse: if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.DiscoveryResponse)) { - NetIncomingMessage dr = CreateIncomingMessage(NetIncomingMessageType.DiscoveryResponse, payloadLengthBytes); - if (payloadLengthBytes > 0) - Buffer.BlockCopy(m_receiveBuffer, ptr, dr.m_data, 0, payloadLengthBytes); - dr.m_bitLength = payloadLengthBits; + NetIncomingMessage dr = CreateIncomingMessage(NetIncomingMessageType.DiscoveryResponse, payloadByteLength); + if (payloadByteLength > 0) + Buffer.BlockCopy(m_receiveBuffer, ptr, dr.m_data, 0, payloadByteLength); + dr.m_bitLength = payloadByteLength * 8; dr.m_senderEndpoint = senderEndpoint; ReleaseMessage(dr); } + return; + case NetMessageType.NatIntroduction: + HandleNatIntroduction(ptr); + return; + case NetMessageType.NatPunchMessage: + HandleNatPunch(ptr, senderEndpoint); + return; + case NetMessageType.Connect: + // proceed break; - - case NetMessageLibraryType.Connect: - - if (!m_configuration.m_acceptIncomingConnections) - { - LogWarning("Connect received; but we're not accepting incoming connections!"); - break; - } - - string appIdent; - long remoteUniqueIdentifier = 0; - NetIncomingMessage approval = null; - try - { - NetIncomingMessage reader = new NetIncomingMessage(); - - reader.m_data = GetStorage(payloadLengthBytes); - Buffer.BlockCopy(m_receiveBuffer, ptr, reader.m_data, 0, payloadLengthBytes); - ptr += payloadLengthBytes; - reader.m_bitLength = payloadLengthBits; - appIdent = reader.ReadString(); - remoteUniqueIdentifier = reader.ReadInt64(); - - int approvalBitLength = (int)reader.ReadVariableUInt32(); - if (approvalBitLength > 0) - { - int approvalByteLength = NetUtility.BytesToHoldBits(approvalBitLength); - if (approvalByteLength < m_configuration.MaximumTransmissionUnit) - { - approval = CreateIncomingMessage(NetIncomingMessageType.ConnectionApproval, approvalByteLength); - reader.ReadBits(approval.m_data, 0, approvalBitLength); - approval.m_bitLength = approvalBitLength; - } - } - } - catch (Exception ex) - { - // malformed connect packet - LogWarning("Malformed connect packet from " + senderEndpoint + " - " + ex.ToString()); - break; - } - - if (appIdent.Equals(m_configuration.AppIdentifier, StringComparison.InvariantCulture) == false) - { - // wrong app ident - LogWarning("Connect received with wrong appidentifier (need '" + m_configuration.AppIdentifier + "' found '" + appIdent + "') from " + senderEndpoint); - - NetOutgoingMessage bye = CreateLibraryMessage(NetMessageLibraryType.Disconnect, "Wrong app identifier!"); - SendUnconnectedLibrary(bye, senderEndpoint); - - break; - } - - // ok, someone wants to connect to us, and we're accepting connections! - int reservedSlots = m_connections.Count; - if (m_pendingConnections != null) - reservedSlots += m_pendingConnections.Count; - if (reservedSlots >= m_configuration.MaximumConnections) - { - HandleServerFull(senderEndpoint); - break; - } - - bool isAlreadyPending = false; - if (m_pendingConnections != null) - { - // check so we don't already have a pending connection to this endpoint - foreach (NetConnection conn in m_pendingConnections) - { - if (conn.RemoteEndpoint.Equals(senderEndpoint)) - { - // Yes, we do. - isAlreadyPending = true; - break; - } - } - } - - if (!isAlreadyPending) - { - NetConnection conn = new NetConnection(this, senderEndpoint); - conn.m_connectionInitiator = false; - conn.m_connectInitationTime = NetTime.Now; - conn.m_remoteUniqueIdentifier = remoteUniqueIdentifier; - - if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.ConnectionApproval)) - { - // do connection approval before accepting this connection - AddPendingConnection(conn, approval); - break; - } - - AcceptConnection(conn); - } - break; + case NetMessageType.Disconnect: + // this is probably ok + LogVerbose("Received Disconnect from unconnected source: " + senderEndpoint); + return; default: - LogWarning("Received unconnected library message of type " + libType); - break; + LogWarning("Received unhandled library message " + tp + " from " + senderEndpoint); + return; } - } - private void HandleUnconnectedUserMessage(int ptr, int payloadLengthBits, IPEndPoint senderEndpoint) - { - VerifyNetworkThread(); + // It's someone wanting to shake hands with us! - NetIncomingMessage ium = CreateIncomingMessage(NetIncomingMessageType.UnconnectedData, m_receiveBuffer, ptr, NetUtility.BytesToHoldBits(payloadLengthBits)); - ium.m_bitLength = payloadLengthBits; - ium.m_senderEndpoint = senderEndpoint; - ReleaseMessage(ium); - } - - private void AcceptConnection(NetConnection conn) - { - lock (m_connections) + int reservedSlots = m_handshakes.Count + m_connections.Count; + if (reservedSlots >= m_configuration.m_maximumConnections) { - m_connections.Add(conn); - m_connectionLookup[conn.m_remoteEndpoint] = conn; + // server full + NetOutgoingMessage full = CreateMessage("Server full"); + full.m_messageType = NetMessageType.Disconnect; + SendLibrary(full, senderEndpoint); + return; } - conn.SetStatus(NetConnectionStatus.Connecting, "Connecting"); - // send connection response - conn.SendConnectResponse(); - - conn.m_connectInitationTime = NetTime.Now; + // Ok, start handshake! + NetConnection conn = new NetConnection(this, senderEndpoint); + m_handshakes.Add(senderEndpoint, conn); + conn.ReceivedHandshake(tp, ptr, payloadByteLength); return; } - internal void RemoveConnection(NetConnection conn) + internal void AcceptConnection(NetConnection conn) { + // LogDebug("Accepted connection " + conn); + + if (m_handshakes.Remove(conn.m_remoteEndpoint) == false) + LogWarning("AcceptConnection called but m_handshakes did not contain it!"); + lock (m_connections) { - m_connections.Remove(conn); - m_connectionLookup.Remove(conn.m_remoteEndpoint); + if (m_connections.Contains(conn)) + { + LogWarning("AcceptConnection called but m_connection already contains it!"); + } + else + { + m_connections.Add(conn); + m_connectionLookup.Add(conn.m_remoteEndpoint, conn); + } } } - private void HandleServerFull(IPEndPoint connecter) + [Conditional("DEBUG")] + internal void VerifyNetworkThread() { - const string rejectMessage = "Server is full!"; // TODO: put in configuration - NetOutgoingMessage reply = CreateLibraryMessage(NetMessageLibraryType.Disconnect, rejectMessage); - SendLibraryImmediately(reply, connecter); + Thread ct = Thread.CurrentThread; + if (Thread.CurrentThread != m_networkThread) + throw new NetException("Executing on wrong thread! Should be library system thread (is " + ct.Name + " mId " + ct.ManagedThreadId + ")"); } - // called by user and network thread - private void EnqueueUnconnectedMessage(NetOutgoingMessage msg, IPEndPoint recipient) + internal NetIncomingMessage SetupReadHelperMessage(int ptr, int payloadLength) { - NetSending send = new NetSending(msg, NetMessageType.UserUnreliable, 0); - send.Recipient = recipient; + VerifyNetworkThread(); - msg.m_numUnfinishedSendings++; - m_unsentUnconnectedMessage.Enqueue(send); + m_readHelperMessage.m_bitLength = (ptr + payloadLength) * 8; + m_readHelperMessage.m_readPosition = (ptr * 8); + return m_readHelperMessage; } - - // called by user and network thread - private void SendUnconnectedLibrary(NetOutgoingMessage msg, IPEndPoint recipient) - { - msg.m_wasSent = true; - NetSending send = new NetSending(msg, NetMessageType.Library, 0); - send.Recipient = recipient; - - msg.m_numUnfinishedSendings++; - m_unsentUnconnectedMessage.Enqueue(send); - } - - internal static NetDeliveryMethod GetDeliveryMethod(NetMessageType mtp) - { - if (mtp >= NetMessageType.UserReliableOrdered) - return NetDeliveryMethod.ReliableOrdered; - else if (mtp >= NetMessageType.UserReliableSequenced) - return NetDeliveryMethod.ReliableSequenced; - else if (mtp >= NetMessageType.UserReliableUnordered) - return NetDeliveryMethod.ReliableUnordered; - else if (mtp >= NetMessageType.UserSequenced) - return NetDeliveryMethod.UnreliableSequenced; - return NetDeliveryMethod.Unreliable; - } - - internal void SendLibraryImmediately(NetOutgoingMessage msg, IPEndPoint destination) - { - msg.m_wasSent = true; - int len = msg.EncodeUnfragmented(m_sendBuffer, 0, NetMessageType.Library, 0); - - bool connectionReset; - SendPacket(len, destination, 1, out connectionReset); - - // TODO: handle connectionReset - - Recycle(msg); - } - } -} \ No newline at end of file +} diff --git a/Lidgren.Network/NetPeer.LatencySimulation.cs b/Lidgren.Network/NetPeer.LatencySimulation.cs index c978f1c..ba2226d 100644 --- a/Lidgren.Network/NetPeer.LatencySimulation.cs +++ b/Lidgren.Network/NetPeer.LatencySimulation.cs @@ -21,6 +21,7 @@ using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; +using System.Diagnostics; namespace Lidgren.Network { @@ -45,34 +46,35 @@ namespace Lidgren.Network float loss = m_configuration.m_loss; if (loss > 0.0f) { - if (NetRandom.Instance.Chance(m_configuration.m_loss)) + if ((float)NetRandom.Instance.NextDouble() < loss) { - //LogVerbose("Sending packet " + numBytes + " bytes - SIMULATED LOST!"); + LogVerbose("Sending packet " + numBytes + " bytes - SIMULATED LOST!"); return; // packet "lost" } } m_statistics.PacketSent(numBytes, numMessages); - + // simulate latency float m = m_configuration.m_minimumOneWayLatency; float r = m_configuration.m_randomOneWayLatency; if (m == 0.0f && r == 0.0f) { // no latency simulation - //LogVerbose("Sending packet " + numBytes + " bytes"); - ActuallySendPacket(m_sendBuffer, numBytes, target, out connectionReset); + // LogVerbose("Sending packet " + numBytes + " bytes"); + bool wasSent = ActuallySendPacket(m_sendBuffer, numBytes, target, out connectionReset); + // TODO: handle wasSent == false? return; } int num = 1; - if (m_configuration.m_duplicates > 0.0f && NetRandom.Instance.Chance(m_configuration.m_duplicates)) + if (m_configuration.m_duplicates > 0.0f && NetRandom.Instance.NextSingle() < m_configuration.m_duplicates) num++; float delay = 0; for (int i = 0; i < num; i++) { - delay = m_configuration.m_minimumOneWayLatency + (NetRandom.Instance.NextFloat() * m_configuration.m_randomOneWayLatency); + delay = m_configuration.m_minimumOneWayLatency + (NetRandom.Instance.NextSingle() * m_configuration.m_randomOneWayLatency); // Enqueue delayed packet DelayedPacket p = new DelayedPacket(); @@ -108,7 +110,7 @@ namespace Lidgren.Network } } - internal void ActuallySendPacket(byte[] data, int numBytes, IPEndPoint target, out bool connectionReset) + internal bool ActuallySendPacket(byte[] data, int numBytes, IPEndPoint target, out bool connectionReset) { connectionReset = false; try @@ -122,6 +124,56 @@ namespace Lidgren.Network } catch (SocketException sx) { + if (sx.SocketErrorCode == SocketError.WouldBlock) + { + // send buffer full? + LogWarning("Socket threw exception; would block - send buffer full? Increase in NetPeerConfiguration"); + return false; + } + if (sx.SocketErrorCode == SocketError.ConnectionReset) + { + // connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable" + connectionReset = true; + return false; + } + LogError("Failed to send packet: " + sx); + } + catch (Exception ex) + { + LogError("Failed to send packet: " + ex); + } + finally + { + if (target.Address == IPAddress.Broadcast) + m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, false); + } + return true; + } + +#else + // + // Release - just send the packet straight away + // + internal void SendPacket(int numBytes, IPEndPoint target, int numMessages, out bool connectionReset) + { + connectionReset = false; + try + { + if (target.Address == IPAddress.Broadcast) + m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); + + int bytesSent = m_socket.SendTo(m_sendBuffer, 0, numBytes, SocketFlags.None, target); + if (numBytes != bytesSent) + LogWarning("Failed to send the full " + numBytes + "; only " + bytesSent + " bytes sent in packet!"); + } + catch (SocketException sx) + { + if (sx.SocketErrorCode == SocketError.WouldBlock) + { + // send buffer full? + LogWarning("Socket threw exception; would block - send buffer full? Increase in NetPeerConfiguration"); + return; + } if (sx.SocketErrorCode == SocketError.ConnectionReset) { // connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable" @@ -139,35 +191,13 @@ namespace Lidgren.Network if (target.Address == IPAddress.Broadcast) m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, false); } + return; } -#else - // - // Release - just send the packet straight away - // - internal void SendPacket(int numBytes, IPEndPoint target, int numMessages, out bool connectionReset) + private void SendCallBack(IAsyncResult res) { - connectionReset = false; - try - { - int bytesSent = m_socket.SendTo(m_sendBuffer, 0, numBytes, SocketFlags.None, target); - if (numBytes != bytesSent) - LogWarning("Failed to send the full " + numBytes + "; only " + bytesSent + " bytes sent in packet!"); - } - catch (SocketException sx) - { - if (sx.SocketErrorCode == SocketError.ConnectionReset) - { - // connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable" - connectionReset = true; - return; - } - LogError("Failed to send packet: " + sx); - } - catch (Exception ex) - { - LogError("Failed to send packet: " + ex); - } + NetException.Assert(res.IsCompleted == true); + m_socket.EndSendTo(res); } #endif } diff --git a/Lidgren.Network/NetPeer.MessagePools.cs b/Lidgren.Network/NetPeer.MessagePools.cs new file mode 100644 index 0000000..23ea1a0 --- /dev/null +++ b/Lidgren.Network/NetPeer.MessagePools.cs @@ -0,0 +1,194 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Lidgren.Network +{ + public partial class NetPeer + { + private List m_storagePool; // sorted smallest to largest + private NetQueue m_outgoingMessagesPool; + private NetQueue m_incomingMessagesPool; + + internal int m_storagePoolBytes; + + private void InitializePools() + { + if (m_configuration.UseMessageRecycling) + { + m_storagePool = new List(16); + m_outgoingMessagesPool = new NetQueue(4); + m_incomingMessagesPool = new NetQueue(4); + } + else + { + m_storagePool = null; + m_outgoingMessagesPool = null; + m_incomingMessagesPool = null; + } + } + + internal byte[] GetStorage(int minimumCapacity) + { + if (m_storagePool == null) + return new byte[minimumCapacity]; + + lock (m_storagePool) + { + for (int i = 0; i < m_storagePool.Count; i++) + { + byte[] retval = m_storagePool[i]; + if (retval != null && retval.Length >= minimumCapacity) + { + m_storagePool[i] = null; + m_storagePoolBytes -= retval.Length; + return retval; + } + } + } + m_statistics.m_bytesAllocated += minimumCapacity; + return new byte[minimumCapacity]; + } + + internal void Recycle(byte[] storage) + { + if (m_storagePool == null) + return; + + int len = storage.Length; + lock (m_storagePool) + { + for (int i = 0; i < m_storagePool.Count; i++) + { + if (m_storagePool[i] == null) + { + m_storagePoolBytes += storage.Length; + m_storagePool[i] = storage; + return; + } + } + m_storagePoolBytes += storage.Length; + m_storagePool.Add(storage); + } + } + + /// + /// Creates a new message for sending + /// + /// initial capacity in bytes + public NetOutgoingMessage CreateMessage() + { + return CreateMessage(m_configuration.m_defaultOutgoingMessageCapacity); + } + + /// + /// Creates a new message for sending and writes the provided string to it + /// + /// initial capacity in bytes + public NetOutgoingMessage CreateMessage(string content) + { + byte[] bytes = Encoding.UTF8.GetBytes(content); + NetOutgoingMessage om = CreateMessage(2 + bytes.Length); + om.WriteVariableUInt32((uint)bytes.Length); + om.Write(bytes); + return om; + } + + /// + /// Creates a new message for sending + /// + /// initial capacity in bytes + public NetOutgoingMessage CreateMessage(int initialCapacity) + { + NetOutgoingMessage retval; + if (m_outgoingMessagesPool == null || !m_outgoingMessagesPool.TryDequeue(out retval)) + retval = new NetOutgoingMessage(); + + byte[] storage = GetStorage(initialCapacity); + retval.m_data = storage; + + return retval; + } + + internal NetIncomingMessage CreateIncomingMessage(NetIncomingMessageType tp, byte[] useStorageData) + { + NetIncomingMessage retval; + if (m_incomingMessagesPool == null || !m_incomingMessagesPool.TryDequeue(out retval)) + retval = new NetIncomingMessage(tp); + else + retval.m_incomingMessageType = tp; + retval.m_data = useStorageData; + return retval; + } + + internal NetIncomingMessage CreateIncomingMessage(NetIncomingMessageType tp, int minimumByteSize) + { + NetIncomingMessage retval; + if (m_incomingMessagesPool == null || !m_incomingMessagesPool.TryDequeue(out retval)) + retval = new NetIncomingMessage(tp); + else + retval.m_incomingMessageType = tp; + retval.m_data = GetStorage(minimumByteSize); + return retval; + } + + /// + /// Recycles a NetIncomingMessage instance for reuse; taking pressure off the garbage collector + /// + public void Recycle(NetIncomingMessage msg) + { + if (m_incomingMessagesPool == null) + return; +#if DEBUG + if (m_incomingMessagesPool.Contains(msg)) + throw new NetException("Recyling already recycled message! Thread race?"); +#endif + byte[] storage = msg.m_data; + msg.m_data = null; + Recycle(storage); + msg.Reset(); + m_incomingMessagesPool.Enqueue(msg); + } + + internal void Recycle(NetOutgoingMessage msg) + { + if (m_outgoingMessagesPool == null) + return; +#if DEBUG + if (m_outgoingMessagesPool.Contains(msg)) + throw new NetException("Recyling already recycled message! Thread race?"); +#endif + + byte[] storage = msg.m_data; + msg.m_data = null; + + // message fragments cannot be recycled + // TODO: find a way to recycle large message after all fragments has been acknowledged + if (msg.m_fragmentGroup == 0) + Recycle(storage); + + msg.Reset(); + m_outgoingMessagesPool.Enqueue(msg); + } + + /// + /// Creates an incoming message with the required capacity for releasing to the application + /// + internal NetIncomingMessage CreateIncomingMessage(NetIncomingMessageType tp, string text) + { + NetIncomingMessage retval; + if (string.IsNullOrEmpty(text)) + { + retval = CreateIncomingMessage(tp, 1); + retval.Write(""); + return retval; + } + + byte[] bytes = System.Text.Encoding.UTF8.GetBytes(text); + retval = CreateIncomingMessage(tp, bytes.Length + (bytes.Length > 127 ? 2 : 1)); + retval.Write(text); + + return retval; + } + } +} diff --git a/Lidgren.Network/NetPeer.Send.cs b/Lidgren.Network/NetPeer.Send.cs new file mode 100644 index 0000000..5de75d6 --- /dev/null +++ b/Lidgren.Network/NetPeer.Send.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Net; + +namespace Lidgren.Network +{ + public partial class NetPeer + { + /// + /// Send a message to a specific connection + /// + /// The message to send + /// The recipient connection + /// How to deliver the message + public NetSendResult SendMessage(NetOutgoingMessage msg, NetConnection recipient, NetDeliveryMethod method) + { + return SendMessage(msg, recipient, method, 0); + } + + /// + /// Send a message to a specific connection + /// + /// The message to send + /// The recipient connection + /// How to deliver the message + /// Sequence channel within the delivery method + public NetSendResult SendMessage(NetOutgoingMessage msg, NetConnection recipient, NetDeliveryMethod method, int sequenceChannel) + { + if (msg == null) + throw new ArgumentNullException("msg"); + if (recipient == null) + throw new ArgumentNullException("recipient"); + if (method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.ReliableUnordered) + NetException.Assert(sequenceChannel == 0, "Delivery method " + method + " cannot use sequence channels other than 0!"); + if (msg.m_isSent) + throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently"); + + int len = msg.LengthBytes; + if (len <= m_configuration.MaximumTransmissionUnit) + { + Interlocked.Increment(ref msg.m_recyclingCount); + return recipient.EnqueueMessage(msg, method, sequenceChannel); + } + else + { + // message must be fragmented! + SendFragmentedMessage(msg, new NetConnection[] { recipient }, method, sequenceChannel); + return NetSendResult.Queued; // could be different for each connection; Queued is "most true" + } + } + + public void SendMessage(NetOutgoingMessage msg, IList recipients, NetDeliveryMethod method, int sequenceChannel) + { + if (msg == null) + throw new ArgumentNullException("msg"); + if (recipients == null) + throw new ArgumentNullException("recipients"); + if (method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.ReliableUnordered) + NetException.Assert(sequenceChannel == 0, "Delivery method " + method + " cannot use sequence channels other than 0!"); + if (msg.m_isSent) + throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently"); + + int len = msg.LengthBytes; + if (len <= m_configuration.MaximumTransmissionUnit) + { + Interlocked.Add(ref msg.m_recyclingCount, recipients.Count); + foreach (NetConnection conn in recipients) + { + if (conn == null) + { + Interlocked.Decrement(ref msg.m_recyclingCount); + continue; + } + NetSendResult res = conn.EnqueueMessage(msg, method, sequenceChannel); + if (res == NetSendResult.Dropped) + Interlocked.Decrement(ref msg.m_recyclingCount); + } + } + else + { + // message must be fragmented! + SendFragmentedMessage(msg, recipients, method, sequenceChannel); + } + + return; + } + + /// + /// Send a message to an unconnected host + /// + public void SendUnconnectedMessage(NetOutgoingMessage msg, string host, int port) + { + if (msg == null) + throw new ArgumentNullException("msg"); + if (host == null) + throw new ArgumentNullException("host"); + if (msg.m_isSent) + throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently"); + if (msg.LengthBytes > m_configuration.MaximumTransmissionUnit) + throw new NetException("Unconnected messages too long! Must be shorter than NetConfiguration.MaximumTransmissionUnit (currently " + m_configuration.MaximumTransmissionUnit + ")"); + + IPAddress adr = NetUtility.Resolve(host); + if (adr == null) + throw new NetException("Failed to resolve " + host); + + msg.m_messageType = NetMessageType.Unconnected; + + // TODO: Interlocked.Add(ref msg.m_recyclingCount, recipients.Count); ? + m_unsentUnconnectedMessages.Enqueue(new NetTuple(new IPEndPoint(adr, port), msg)); + } + + /// + /// Send a message to an unconnected host + /// + public void SendUnconnectedMessage(NetOutgoingMessage msg, IPEndPoint recipient) + { + if (msg == null) + throw new ArgumentNullException("msg"); + if (recipient == null) + throw new ArgumentNullException("recipient"); + if (msg.m_isSent) + throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently"); + if (msg.LengthBytes > m_configuration.MaximumTransmissionUnit) + throw new NetException("Unconnected messages too long! Must be shorter than NetConfiguration.MaximumTransmissionUnit (currently " + m_configuration.MaximumTransmissionUnit + ")"); + + msg.m_messageType = NetMessageType.Unconnected; + + // TODO: Interlocked.Add(ref msg.m_recyclingCount, recipients.Count); ? + m_unsentUnconnectedMessages.Enqueue(new NetTuple(recipient, msg)); + } + + /// + /// Send a message to an unconnected host + /// + public void SendUnconnectedMessage(NetOutgoingMessage msg, IList recipients) + { + if (msg == null) + throw new ArgumentNullException("msg"); + if (recipients == null) + throw new ArgumentNullException("recipients"); + if (msg.m_isSent) + throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently"); + if (msg.LengthBytes > m_configuration.MaximumTransmissionUnit) + throw new NetException("Unconnected messages too long! Must be shorter than NetConfiguration.MaximumTransmissionUnit (currently " + m_configuration.MaximumTransmissionUnit + ")"); + + msg.m_messageType = NetMessageType.Unconnected; + + Interlocked.Add(ref msg.m_recyclingCount, recipients.Count); + foreach(IPEndPoint ep in recipients) + m_unsentUnconnectedMessages.Enqueue(new NetTuple(ep, msg)); + } + } +} diff --git a/Lidgren.Network/NetPeer.cs b/Lidgren.Network/NetPeer.cs index c8a0602..24611a1 100644 --- a/Lidgren.Network/NetPeer.cs +++ b/Lidgren.Network/NetPeer.cs @@ -1,85 +1,56 @@ -/* Copyright (c) 2010 Michael Lidgren - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software -and associated documentation files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom -the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Net; +using System; using System.Threading; +using System.Collections.Generic; +using System.Net; namespace Lidgren.Network { - // - // This partial file holds public netpeer methods accessible to the application - // - [DebuggerDisplay("Status={m_status}")] + /// + /// Represents a local peer capable of holding zero, one or more connections to remote peers + /// public partial class NetPeer { - private static int s_peerCount = 0; + private static int s_initializedPeersCount; - internal const int kMinPacketHeaderSize = 2; - internal const int kMaxPacketHeaderSize = 5; - - private NetPeerStatus m_status; - private readonly object m_initializeLock = new object(); - internal long m_uniqueIdentifier; - - internal NetPeerConfiguration m_configuration; - internal readonly NetPeerStatistics m_statistics; - private Thread m_networkThread; - private string m_shutdownReason; - private string m_networkThreadName; + private int m_listenPort; internal readonly List m_connections; private readonly Dictionary m_connectionLookup; + private string m_shutdownReason; + /// /// Gets the status of the NetPeer /// public NetPeerStatus Status { get { return m_status; } } /// - /// Name of the network thread for this NetPeer + /// Signalling event which can be waited on to determine when a message is queued for reading. + /// Note that there is no guarantee that after the event is signaled the blocked thread will + /// find the message in the queue. Other user created threads could be preempted and dequeue + /// the message before the waiting thread wakes up. /// - public string NetworkThreadName - { - get { return m_networkThreadName; } - set - { - if (m_networkThreadName != value) - { - m_networkThreadName = value; - if (m_networkThread != null) - m_networkThread.Name = m_networkThreadName; - } - } - } + public AutoResetEvent MessageReceivedEvent { get { return m_messageReceivedEvent; } } + + /// + /// Gets a unique identifier for this NetPeer based on Mac address and ip/port. Note! Not available until Start has been called! + /// + public long UniqueIdentifier { get { return m_uniqueIdentifier; } } + + /// + /// Gets the port number this NetPeer is listening and sending on + /// + public int Port { get { return m_listenPort; } } /// /// Gets a copy of the list of connections /// - public NetConnection[] Connections + public List Connections { get { lock (m_connections) - return m_connections.ToArray(); + return new List(m_connections); } } @@ -104,48 +75,22 @@ namespace Lidgren.Network /// public NetPeerConfiguration Configuration { get { return m_configuration; } } - /// - /// Gets the port number this NetPeer is listening and sending on - /// - public int Port { get { return m_listenPort; } } - - /// - /// Gets a semi-unique identifier based on Mac address and ip/port. Note! Not available until Start has been called! - /// - public long UniqueIdentifier { get { return m_uniqueIdentifier; } } - - public NetPeer(NetPeerConfiguration configuration) + public NetPeer(NetPeerConfiguration config) { - if (configuration == null) - throw new ArgumentNullException("configuration"); - - m_status = NetPeerStatus.NotRunning; - m_configuration = configuration; - m_connections = new List(m_configuration.MaximumConnections); - m_connectionLookup = new Dictionary(m_configuration.MaximumConnections); - m_senderRemote = (EndPoint)new IPEndPoint(IPAddress.Any, 0); + m_configuration = config; m_statistics = new NetPeerStatistics(this); - - int pc = Interlocked.Increment(ref s_peerCount); - m_networkThreadName = "Lidgren network thread " + pc.ToString(); + m_releasedIncomingMessages = new NetQueue(4); + m_unsentUnconnectedMessages = new NetQueue>(2); + m_connections = new List(); + m_connectionLookup = new Dictionary(); + m_handshakes = new Dictionary(); + m_senderRemote = (EndPoint)new IPEndPoint(IPAddress.Any, 0); + m_status = NetPeerStatus.NotRunning; + m_receivedFragmentGroups = new Dictionary(); } /// - /// Returns the connection to a remote endpoint; if it exists - /// - public NetConnection GetConnection(IPEndPoint remoteEndPoint) - { - if (remoteEndPoint == null) - throw new ArgumentNullException("remoteEndPoint"); - - NetConnection retval; - if (m_connectionLookup.TryGetValue(remoteEndPoint, out retval)) - return retval; - return null; - } - - /// - /// Binds to socket + /// Binds to socket and spawns networking thread /// public void Start() { @@ -158,16 +103,18 @@ namespace Lidgren.Network m_status = NetPeerStatus.Starting; - m_releasedIncomingMessages.Clear(); - m_unsentUnconnectedMessage.Clear(); - - m_configuration.VerifyAndLock(); + // fix network thread name + if (m_configuration.NetworkThreadName == "Lidgren network thread") + { + int pc = Interlocked.Increment(ref s_initializedPeersCount); + m_configuration.NetworkThreadName = "Lidgren network thread " + pc.ToString(); + } InitializeNetwork(); - + // start network thread m_networkThread = new Thread(new ThreadStart(NetworkLoop)); - m_networkThread.Name = m_networkThreadName; + m_networkThread.Name = m_configuration.NetworkThreadName; m_networkThread.IsBackground = true; m_networkThread.Start(); @@ -175,17 +122,11 @@ namespace Lidgren.Network Thread.Sleep(10); } - /// - /// Returns true if there is a queued message available to read using ReadMessage() - /// - public bool MessageAvailable + internal NetConnection GetConnection(IPEndPoint ep) { - get - { - if (m_status == NetPeerStatus.NotRunning) - return false; - return (m_releasedIncomingMessages.Count > 0); - } + NetConnection retval; + m_connectionLookup.TryGetValue(ep, out retval); + return retval; } /// @@ -193,9 +134,6 @@ namespace Lidgren.Network /// public NetIncomingMessage ReadMessage() { - if (m_status == NetPeerStatus.NotRunning) - return null; - NetIncomingMessage retval; if (m_releasedIncomingMessages.TryDequeue(out retval)) { @@ -207,14 +145,16 @@ namespace Lidgren.Network } return retval; } - - public NetIncomingMessage WaitMessage(int maxMillis) + + // send message immediately + internal void SendLibrary(NetOutgoingMessage msg, IPEndPoint recipient) { - if (m_messageReceivedEvent != null) - m_messageReceivedEvent.WaitOne(maxMillis); - NetIncomingMessage retval; - m_releasedIncomingMessages.TryDequeue(out retval); - return retval; + VerifyNetworkThread(); + NetException.Assert(msg.m_isSent == false); + + bool connReset; + int len = msg.Encode(m_sendBuffer, 0, 0); + SendPacket(len, recipient, 1, out connReset); } /// @@ -225,6 +165,14 @@ namespace Lidgren.Network return Connect(new IPEndPoint(NetUtility.Resolve(host), port), null); } + /// + /// Create a connection to a remote endpoint + /// + public NetConnection Connect(string host, int port, NetOutgoingMessage hailMessage) + { + return Connect(new IPEndPoint(NetUtility.Resolve(host), port), hailMessage); + } + /// /// Create a connection to a remote endpoint /// @@ -236,34 +184,7 @@ namespace Lidgren.Network /// /// Create a connection to a remote endpoint /// - public NetConnection Connect(string host, int port, NetOutgoingMessage approvalMessage) - { - return Connect(new IPEndPoint(NetUtility.Resolve(host), port), approvalMessage); - } - - /// - /// Tries to create a connection to a remote endpoint; returns true on success - /// Note that the connection attempt may still fail; the returning value only indicates that the connection procedure initiated successfully - /// - public bool TryConnect(IPEndPoint remoteEndpoint, NetOutgoingMessage approvalMessage, out NetConnection connection) - { - lock (m_connections) - { - if (m_status == NetPeerStatus.NotRunning || m_connectionLookup.ContainsKey(remoteEndpoint)) - { - connection = null; - return false; - } - - connection = Connect(remoteEndpoint, approvalMessage); - return true; - } - } - - /// - /// Create a connection to a remote endpoint - /// - public virtual NetConnection Connect(IPEndPoint remoteEndpoint, NetOutgoingMessage approvalMessage) + public virtual NetConnection Connect(IPEndPoint remoteEndpoint, NetOutgoingMessage hailMessage) { if (remoteEndpoint == null) throw new ArgumentNullException("remoteEndpoint"); @@ -276,158 +197,49 @@ namespace Lidgren.Network if (m_connectionLookup.ContainsKey(remoteEndpoint)) throw new NetException("Already connected to that endpoint!"); + NetConnection hs; + if (m_handshakes.TryGetValue(remoteEndpoint, out hs)) + { + // already trying to connect to that endpoint; make another try + switch (hs.Status) + { + case NetConnectionStatus.InitiatedConnect: + // send another connect + hs.m_connectRequested = true; + break; + case NetConnectionStatus.RespondedConnect: + // send another response + hs.SendConnectResponse(false); + break; + default: + // weird + LogWarning("Weird situation; Connect() already in progress to remote endpoint; but hs status is " + hs.Status); + break; + } + } + NetConnection conn = new NetConnection(this, remoteEndpoint); - conn.m_approvalMessage = approvalMessage; + conn.m_localHailMessage = hailMessage; // handle on network thread conn.m_connectRequested = true; conn.m_connectionInitiator = true; - m_connections.Add(conn); - m_connectionLookup[remoteEndpoint] = conn; + m_handshakes.Add(remoteEndpoint, conn); return conn; } } - /// - /// Send a message to an existing connection - /// - public bool SendMessage(NetOutgoingMessage msg, NetConnection recipient, NetDeliveryMethod deliveryMethod) +#if DEBUG + public void RawSend(byte[] arr, int offset, int length, IPEndPoint destination) { - return SendMessage(msg, recipient, deliveryMethod, 0); - } - - /// - /// Send a message to an existing connection - /// - /// The NetOutgoingMessage to send - /// The recipient connection - /// How to deliver the message - /// Delivery channel (0-31) - /// True if the message was queued for delivery, else false - public bool SendMessage(NetOutgoingMessage msg, NetConnection recipient, NetDeliveryMethod deliveryMethod, int channel) - { - if (msg == null) - throw new ArgumentNullException("msg"); - if (recipient == null) - throw new ArgumentNullException("recipient"); - - if (msg.IsSent) - throw new NetException("Message has already been sent! To send to multiple recipients use SendMessage(... IEnumerable 63) - throw new NetException("Channel must be between 0 and 63"); - if (channel != 0 && (deliveryMethod == NetDeliveryMethod.Unreliable || deliveryMethod == NetDeliveryMethod.ReliableUnordered)) - throw new NetException("Channel must be 0 for Unreliable and ReliableUnordered"); - - if (m_status != NetPeerStatus.Running) - return false; - - return recipient.SendMessage(msg, deliveryMethod, channel); - } - - /// - /// Send a message to a number of existing connections; returns true if all recipients were sent the message - /// - /// Delivery channel (0-31) - public bool SendMessage(NetOutgoingMessage msg, IEnumerable recipients, NetDeliveryMethod deliveryMethod, int sequenceChannel) - { - if (msg == null) - throw new ArgumentNullException("msg"); - if (recipients == null) - throw new ArgumentNullException("recipients"); - - if (msg.IsSent) - throw new NetException("Message has already been sent!"); - if (sequenceChannel < 0 || sequenceChannel > NetConstants.NetChannelsPerDeliveryMethod) - throw new NetException("Channel must be between 0 and " + (NetConstants.NetChannelsPerDeliveryMethod - 1)); - if (sequenceChannel != 0 && (deliveryMethod == NetDeliveryMethod.Unreliable || deliveryMethod == NetDeliveryMethod.ReliableUnordered)) - throw new NetException("Channel must be 0 for Unreliable and ReliableUnordered"); - - if (m_status != NetPeerStatus.Running) - return false; - - msg.m_wasSent = true; - - NetMessageType tp = (NetMessageType)((int)deliveryMethod + sequenceChannel); - - bool all = true; - foreach (NetConnection conn in recipients) - { - if (!conn.EnqueueSendMessage(msg, tp)) - all = false; - } - - return all; - } - - /// - /// Send a message to an unconnected host - /// - public void SendUnconnectedMessage(NetOutgoingMessage msg, string host, int port) - { - if (msg == null) - throw new ArgumentNullException("msg"); - if (host == null) - throw new ArgumentNullException("host"); - - IPAddress adr = NetUtility.Resolve(host); - if (adr == null) - throw new NetException("Failed to resolve " + host); - - SendUnconnectedMessage(msg, new IPEndPoint(adr, port)); - } - - /// - /// Send a message to an unconnected host - /// - public void SendUnconnectedMessage(NetOutgoingMessage msg, IPEndPoint recipient) - { - if (msg == null) - throw new ArgumentNullException("msg"); - if (recipient == null) - throw new ArgumentNullException("recipient"); - - if (msg.IsSent) - throw new NetException("Message has already been sent!"); - msg.m_wasSent = true; - - EnqueueUnconnectedMessage(msg, recipient); - } - - /// - /// Send a message to a number of unconnected hosts - /// - public void SendUnconnectedMessage(NetOutgoingMessage msg, IEnumerable recipients) - { - if (msg == null) - throw new ArgumentNullException("msg"); - if (recipients == null) - throw new ArgumentNullException("recipients"); - if (msg.IsSent) - throw new NetException("Message has already been sent!"); - msg.m_wasSent = true; - - foreach (IPEndPoint rec in recipients) - EnqueueUnconnectedMessage(msg, rec); - } - - /// - /// Send a discovery response message - /// - public void SendDiscoveryResponse(NetOutgoingMessage msg, IPEndPoint recipient) - { - if (recipient == null) - throw new ArgumentNullException("recipient"); - - if (msg == null) - msg = CreateMessage(0); - else if (msg.IsSent) - throw new NetException("Message has already been sent!"); - - msg.m_libType = NetMessageLibraryType.DiscoveryResponse; - SendUnconnectedLibrary(msg, recipient); + // wrong thread - this miiiight crash with network thread... but what's a boy to do. + Array.Copy(arr, offset, m_sendBuffer, 0, length); + bool unused; + SendPacket(length, destination, 1, out unused); } +#endif /// /// Disconnects all active connections and closes the socket @@ -435,7 +247,6 @@ namespace Lidgren.Network public void Shutdown(string bye) { // called on user thread - if (m_socket == null) return; // already shut down @@ -443,12 +254,5 @@ namespace Lidgren.Network m_shutdownReason = bye; m_status = NetPeerStatus.ShutdownRequested; } - - public override string ToString() - { - if (m_socket == null) - return "[NetPeer unbound]"; - return "[NetPeer bound to " + m_socket.LocalEndPoint + " " + ConnectionsCount + " connections]"; - } } } diff --git a/Lidgren.Network/NetPeerConfiguration.cs b/Lidgren.Network/NetPeerConfiguration.cs index 065d8a8..fbb8061 100644 --- a/Lidgren.Network/NetPeerConfiguration.cs +++ b/Lidgren.Network/NetPeerConfiguration.cs @@ -30,28 +30,21 @@ namespace Lidgren.Network private const string c_isLockedMessage = "You may not modify the NetPeerConfiguration after it has been used to initialize a NetPeer"; private bool m_isLocked; + private readonly string m_appIdentifier; + private string m_networkThreadName; + private IPAddress m_localAddress; internal bool m_acceptIncomingConnections; - internal string m_appIdentifier; - internal IPAddress m_localAddress; - internal int m_port; - internal int m_receiveBufferSize, m_sendBufferSize; - internal int m_defaultOutgoingMessageCapacity; - internal int m_maximumTransmissionUnit; - internal bool m_useMessageCoalescing; internal int m_maximumConnections; - internal NetIncomingMessageType m_disabledTypes; - internal int m_throttleBytesPerSecond; - internal int m_throttlePeakBytes; - internal int m_maxRecycledBytesKept; - - // handshake, timeout and keepalive - internal float m_handshakeAttemptDelay; - internal int m_handshakeMaxAttempts; + internal int m_maximumTransmissionUnit; + internal int m_defaultOutgoingMessageCapacity; + internal float m_pingInterval; + internal bool m_useMessageRecycling; internal float m_connectionTimeout; - internal float m_pingFrequency; - // reliability - internal float m_maxAckDelayTime; + internal NetIncomingMessageType m_disabledTypes; + internal int m_port; + internal int m_receiveBufferSize; + internal int m_sendBufferSize; // bad network simulation internal float m_loss; @@ -65,108 +58,47 @@ namespace Lidgren.Network throw new NetException("App identifier must be at least one character long"); m_appIdentifier = appIdentifier.ToString(System.Globalization.CultureInfo.InvariantCulture); - // defaults - m_isLocked = false; - m_acceptIncomingConnections = true; + // + // default values + // + m_disabledTypes = NetIncomingMessageType.ConnectionApproval | NetIncomingMessageType.UnconnectedData | NetIncomingMessageType.VerboseDebugMessage; + m_networkThreadName = "Lidgren network thread"; m_localAddress = IPAddress.Any; m_port = 0; m_receiveBufferSize = 131071; m_sendBufferSize = 131071; - m_connectionTimeout = 25; - m_maximumConnections = 16; - m_defaultOutgoingMessageCapacity = 8; - m_pingFrequency = 6.0f; - m_throttleBytesPerSecond = 1024 * 256; - m_throttlePeakBytes = 8192; - m_maxAckDelayTime = 0.01f; - m_handshakeAttemptDelay = 1.0f; - m_handshakeMaxAttempts = 7; - m_maxRecycledBytesKept = 128 * 1024; - m_useMessageCoalescing = true; + m_acceptIncomingConnections = false; + m_maximumConnections = 32; + m_defaultOutgoingMessageCapacity = 16; + m_pingInterval = 3.0f; + m_connectionTimeout = 25.0f; + m_useMessageRecycling = true; + + // Maximum transmission unit + // Ethernet can take 1500 bytes of payload, so lets stay below that. + // The aim is for a max full packet to be 1440 bytes (30 x 48 bytes, lower than 1468) + // -20 bytes IP header + // -8 bytes UDP header + // -4 bytes to be on the safe side and align to 8-byte boundary + // Total 1408 bytes + // Note that lidgren headers (5 bytes) are not included here; since it's part of the "mtu payload" + m_maximumTransmissionUnit = 1408; m_loss = 0.0f; m_minimumOneWayLatency = 0.0f; m_randomOneWayLatency = 0.0f; m_duplicates = 0.0f; - // default disabled types - m_disabledTypes = NetIncomingMessageType.ConnectionApproval | NetIncomingMessageType.UnconnectedData | NetIncomingMessageType.VerboseDebugMessage; - - // Maximum transmission unit - // Ethernet can take 1500 bytes of payload, so lets stay below that. - // The aim is for a max full packet to be 1440 bytes (30 x 48 bytes, lower than 1468) - // 20 bytes IP header - // 8 bytes UDP header - // 5 bytes lidgren header for one message - // 1 byte just to be on the safe side - // Totals 1440 minus 34 = 1406 bytes free for payload - m_maximumTransmissionUnit = 1406; + m_isLocked = false; } - public NetPeerConfiguration Clone() + internal void Lock() { - NetPeerConfiguration retval = this.MemberwiseClone() as NetPeerConfiguration; - retval.m_isLocked = false; - return retval; - } - - internal void VerifyAndLock() - { - if (m_throttleBytesPerSecond != 0 && m_throttleBytesPerSecond < m_maximumTransmissionUnit) - m_throttleBytesPerSecond = m_maximumTransmissionUnit; - m_isLocked = true; } -#if DEBUG /// - /// Gets or sets the simulated amount of sent packets lost from 0.0f to 1.0f - /// - public float SimulatedLoss - { - get { return m_loss; } - set { m_loss = value; } - } - - /// - /// Gets or sets the minimum simulated amount of one way latency for sent packets in seconds - /// - public float SimulatedMinimumLatency - { - get { return m_minimumOneWayLatency; } - set { m_minimumOneWayLatency = value; } - } - - /// - /// Gets or sets the simulated added random amount of one way latency for sent packets in seconds - /// - public float SimulatedRandomLatency - { - get { return m_randomOneWayLatency; } - set { m_randomOneWayLatency = value; } - } - - /// - /// Gets the average simulated one way latency in seconds - /// - public float SimulatedAverageLatency - { - get { return m_minimumOneWayLatency + (m_randomOneWayLatency * 0.5f); } - } - - /// - /// Gets or sets the simulated amount of duplicated packets from 0.0f to 1.0f - /// - public float SimulatedDuplicatesChance - { - get { return m_duplicates; } - set { m_duplicates = value; } - } - -#endif - - /// - /// Gets or sets the identifier of this application; the library can only connect to matching app identifier peers + /// Gets the identifier of this application; the library can only connect to matching app identifier peers /// public string AppIdentifier { @@ -209,28 +141,19 @@ namespace Lidgren.Network } /// - /// Gets or sets the maximum amount of bytes to send in a single packet, excluding ip, udp and lidgren headers + /// Gets or sets the name of the library network thread. Cannot be changed once NetPeer is initialized. /// - public int MaximumTransmissionUnit + public string NetworkThreadName { - get { return m_maximumTransmissionUnit; } + get { return m_networkThreadName; } set { - if (value < 1 || value >= 4096) - throw new NetException("MaximumTransmissionUnit must be between 1 and 4095 bytes"); - m_maximumTransmissionUnit = value; + if (m_isLocked) + throw new NetException("NetworkThreadName may not be set after the NetPeer which uses the configuration has been started"); + m_networkThreadName = value; } } - /// - /// Gets or sets if message coalescing (sending multiple messages in a single packet) should be used. Normally this should be true. - /// - public bool UseMessageCoalescing - { - get { return m_useMessageCoalescing; } - set { m_useMessageCoalescing = value; } - } - /// /// Gets or sets the maximum amount of connections this peer can hold. Cannot be changed once NetPeer is initialized. /// @@ -246,12 +169,17 @@ namespace Lidgren.Network } /// - /// Gets or sets if the NetPeer should accept incoming connections. This is automatically set to true in NetServer and false in NetClient. + /// Gets or sets the maximum amount of bytes to send in a single packet, excluding ip, udp and lidgren headers /// - public bool AcceptIncomingConnections + public int MaximumTransmissionUnit { - get { return m_acceptIncomingConnections; } - set { m_acceptIncomingConnections = value; } + get { return m_maximumTransmissionUnit; } + set + { + if (value < 1 || value >= ((ushort.MaxValue + 1) / 8)) + throw new NetException("MaximumTransmissionUnit must be between 1 and " + (((ushort.MaxValue + 1) / 8) - 1) + " bytes"); + m_maximumTransmissionUnit = value; + } } /// @@ -263,6 +191,43 @@ namespace Lidgren.Network set { m_defaultOutgoingMessageCapacity = value; } } + /// + /// Gets or sets the time between latency calculating pings + /// + public float PingInterval + { + get { return m_pingInterval; } + set { m_pingInterval = value; } + } + + /// + /// Gets or sets if the library should recycling messages to avoid excessive garbage collection. Cannot be changed once NetPeer is initialized. + /// + public bool UseMessageRecycling + { + get { return m_useMessageRecycling; } + set + { + if (m_isLocked) + throw new NetException(c_isLockedMessage); + m_useMessageRecycling = value; + } + } + + /// + /// Gets or sets the number of seconds timeout will be postponed on a successful ping/pong + /// + public float ConnectionTimeout + { + get { return m_connectionTimeout; } + set + { + if (value < m_pingInterval) + throw new NetException("Connection timeout cannot be lower than ping interval!"); + m_connectionTimeout = value; + } + } + /// /// Gets or sets the local ip address to bind to. Defaults to IPAddress.Any. Cannot be changed once NetPeer is initialized. /// @@ -320,86 +285,65 @@ namespace Lidgren.Network } /// - /// Gets or sets the number of seconds of non-response before disconnecting because of time out. Cannot be changed once NetPeer is initialized. + /// Gets or sets if the NetPeer should accept incoming connections. This is automatically set to true in NetServer and false in NetClient. /// - public float ConnectionTimeout + public bool AcceptIncomingConnections { - get { return m_connectionTimeout; } - set - { - if (m_isLocked) - throw new NetException(c_isLockedMessage); - m_connectionTimeout = value; - } + get { return m_acceptIncomingConnections; } + set { m_acceptIncomingConnections = value; } + } + +#if DEBUG + /// + /// Gets or sets the simulated amount of sent packets lost from 0.0f to 1.0f + /// + public float SimulatedLoss + { + get { return m_loss; } + set { m_loss = value; } } /// - /// Gets or sets the number of seconds between latency calculation (rtt) pings + /// Gets or sets the minimum simulated amount of one way latency for sent packets in seconds /// - public float PingFrequency + public float SimulatedMinimumLatency { - get { return m_pingFrequency; } - set { m_pingFrequency = value; } + get { return m_minimumOneWayLatency; } + set { m_minimumOneWayLatency = value; } } /// - /// Gets or sets the number of allowed bytes to be sent per second per connection; 0 means unlimited (throttling disabled) + /// Gets or sets the simulated added random amount of one way latency for sent packets in seconds /// - public int ThrottleBytesPerSecond + public float SimulatedRandomLatency { - get { return m_throttleBytesPerSecond; } - set - { - if (m_throttleBytesPerSecond != 0 && m_throttleBytesPerSecond < m_maximumTransmissionUnit) - throw new NetException("ThrottleBytesPerSecond can not be lower than MaximumTransmissionUnit"); - m_throttleBytesPerSecond = value; - } + get { return m_randomOneWayLatency; } + set { m_randomOneWayLatency = value; } } /// - /// Gets or sets the peak number of bytes sent before throttling kicks in, if enabled + /// Gets the average simulated one way latency in seconds /// - public int ThrottlePeakBytes + public float SimulatedAverageLatency { - get { return m_throttlePeakBytes; } - set - { - if (m_throttlePeakBytes < m_maximumTransmissionUnit) - throw new NetException("ThrottlePeakBytes can not be lower than MaximumTransmissionUnit"); - m_throttlePeakBytes = value; - } + get { return m_minimumOneWayLatency + (m_randomOneWayLatency * 0.5f); } } /// - /// Gets or sets the number between handshake attempts in seconds + /// Gets or sets the simulated amount of duplicated packets from 0.0f to 1.0f /// - public float HandshakeAttemptDelay + public float SimulatedDuplicatesChance { - get { return m_handshakeAttemptDelay; } - set { m_handshakeAttemptDelay = value; } + get { return m_duplicates; } + set { m_duplicates = value; } } +#endif - /// - /// Gets or sets the maximum number of handshake attempts before declaring failure to shake hands - /// - public int HandshakeMaxAttempts + public NetPeerConfiguration Clone() { - get { return m_handshakeMaxAttempts; } - set { m_handshakeMaxAttempts = value; } - } - - /// - /// Gets or sets the maximum number of bytes kept in the recycle pool. Cannot be changed once NetPeer is initialized. - /// - public int MaxRecycledBytesKept - { - get { return m_maxRecycledBytesKept; } - set - { - if (m_isLocked) - throw new NetException(c_isLockedMessage); - m_maxRecycledBytesKept = value; - } + NetPeerConfiguration retval = this.MemberwiseClone() as NetPeerConfiguration; + retval.m_isLocked = false; + return retval; } } } diff --git a/Lidgren.Network/NetPeerStatistics.cs b/Lidgren.Network/NetPeerStatistics.cs index f569480..af78bd4 100644 --- a/Lidgren.Network/NetPeerStatistics.cs +++ b/Lidgren.Network/NetPeerStatistics.cs @@ -23,6 +23,9 @@ using System.Diagnostics; namespace Lidgren.Network { + /// + /// Statistics for a NetPeer instance + /// public sealed class NetPeerStatistics { private readonly NetPeer m_peer; @@ -96,7 +99,7 @@ namespace Lidgren.Network /// /// Gets the number of bytes in the recycled pool /// - public int BytesInRecyclePool { get { return m_peer.m_storedBytes; } } + public int BytesInRecyclePool { get { return m_peer.m_storagePoolBytes; } } [Conditional("DEBUG")] internal void PacketSent(int numBytes, int numMessages) @@ -113,7 +116,7 @@ namespace Lidgren.Network m_receivedBytes += numBytes; m_receivedMessages += numMessages; } - + public override string ToString() { StringBuilder bdr = new StringBuilder(); @@ -121,7 +124,7 @@ namespace Lidgren.Network bdr.AppendLine("Sent " + m_sentBytes + " bytes in " + m_sentMessages + " messages in " + m_sentPackets + " packets"); bdr.AppendLine("Received " + m_receivedBytes + " bytes in " + m_receivedMessages + " messages in " + m_receivedPackets + " packets"); bdr.AppendLine("Allocated " + m_bytesAllocated + " bytes"); - bdr.AppendLine("Recycled pool " + m_peer.m_storedBytes + " bytes"); + bdr.AppendLine("Recycled pool " + m_peer.m_storagePoolBytes + " bytes"); return bdr.ToString(); } } diff --git a/Lidgren.Network/NetPeerStatus.cs b/Lidgren.Network/NetPeerStatus.cs index 5243005..5589184 100644 --- a/Lidgren.Network/NetPeerStatus.cs +++ b/Lidgren.Network/NetPeerStatus.cs @@ -21,6 +21,9 @@ using System; namespace Lidgren.Network { + /// + /// Status for a NetPeer instance + /// public enum NetPeerStatus { NotRunning = 0, diff --git a/Lidgren.Network/NetQueue.cs b/Lidgren.Network/NetQueue.cs index 53859e1..0c3c9b8 100644 --- a/Lidgren.Network/NetQueue.cs +++ b/Lidgren.Network/NetQueue.cs @@ -62,20 +62,11 @@ namespace Lidgren.Network /// public void Enqueue(T item) { -#if DEBUG - if (typeof(T) == typeof(NetSending)) - { - NetSending om = item as NetSending; - if (om != null) - if (om.MessageType == NetMessageType.Error) - throw new NetException("Enqueuing NetSending with MessageType.Error!"); - } -#endif lock (m_lock) { if (m_size == m_items.Length) SetCapacity(m_items.Length + 8); - + int slot = (m_head + m_size) % m_items.Length; m_items[slot] = item; m_size++; @@ -91,7 +82,7 @@ namespace Lidgren.Network { if (m_size >= m_items.Length) SetCapacity(m_items.Length + 8); - + m_head--; if (m_head < 0) m_head = m_items.Length - 1; diff --git a/Lidgren.Network/NetRandom.cs b/Lidgren.Network/NetRandom.cs index 2d58ad3..b33c26f 100644 --- a/Lidgren.Network/NetRandom.cs +++ b/Lidgren.Network/NetRandom.cs @@ -1,13 +1,11 @@ using System; -using System.Diagnostics; -using System.Threading; namespace Lidgren.Network { /// /// A fast random number generator for .NET /// Colin Green, January 2005 - /// + /// /// September 4th 2005 /// Added NextBytesUnsafe() - commented out by default. /// Fixed bug in Reinitialise() - y,z and w variables were not being reset. @@ -21,7 +19,7 @@ namespace Lidgren.Network /// how this can be easily extened if you need a longer period. At the time of writing I could find no /// information on the period of System.Random for comparison. /// - /// 2) Faster than System.Random. Up to 15x faster, depending on which methods are called. + /// 2) Faster than System.Random. Up to 8x faster, depending on which methods are called. /// /// 3) Direct replacement for System.Random. This class implements all of the methods that System.Random /// does plus some additional methods. The like named methods are functionally equivalent. @@ -37,49 +35,28 @@ namespace Lidgren.Network /// A further performance improvement can be obtained by declaring local variables as static, thus avoiding /// re-allocation of variables on each call. However care should be taken if multiple instances of /// FastRandom are in use or if being used in a multi-threaded environment. - /// - /// - public sealed class NetRandom : Random + public class NetRandom { - public static NetRandom Instance = new NetRandom(); - - protected override double Sample() - { - return NextDouble(); - } + public static readonly NetRandom Instance = new NetRandom(); // The +1 ensures NextDouble doesn't generate 1.0 - private const double c_realUnitInt = 1.0 / ((double)int.MaxValue + 1.0); - private const double c_realUnitUint = 1.0 / ((double)uint.MaxValue + 1.0); - private const uint c_y = 842502087, c_z = 3579807591, c_w = 273326509; + const double REAL_UNIT_INT = 1.0 / ((double)int.MaxValue + 1.0); + const double REAL_UNIT_UINT = 1.0 / ((double)uint.MaxValue + 1.0); + const uint Y = 842502087, Z = 3579807591, W = 273326509; private static int s_extraSeed = 42; - uint m_x, m_y, m_z, m_w; + uint x, y, z, w; - /// - /// Returns a random seed based on time and working set - /// - public static int GetRandomSeed(object forObject) - { - // mix some semi-random properties - int seed = (int)Environment.TickCount; - seed ^= forObject.GetHashCode(); - seed ^= (int)(Stopwatch.GetTimestamp()); - seed ^= (int)(Environment.WorkingSet); // will return 0 on mono - - int extraSeed = Interlocked.Increment(ref s_extraSeed); - - return seed + extraSeed; - } + #region Constructors /// /// Initialises a new instance using time dependent seed. /// public NetRandom() { - // Initialise using the system tick count - Reinitialise(GetRandomSeed(this)); + // Initialise using the system tick count. + Reinitialise(GetSeed(this)); } /// @@ -92,6 +69,23 @@ namespace Lidgren.Network Reinitialise(seed); } + public int GetSeed(object forObject) + { + // mix some semi-random properties + int seed = (int)Environment.TickCount; + seed ^= forObject.GetHashCode(); + //seed ^= (int)(Stopwatch.GetTimestamp()); + //seed ^= (int)(Environment.WorkingSet); // will return 0 on mono + + int extraSeed = System.Threading.Interlocked.Increment(ref s_extraSeed); + + return seed + extraSeed; + } + + #endregion + + #region Public Methods [Reinitialisation] + /// /// Reinitialises using an int value as a seed. /// @@ -101,88 +95,97 @@ namespace Lidgren.Network // The only stipulation stated for the xorshift RNG is that at least one of // the seeds x,y,z,w is non-zero. We fulfill that requirement by only allowing // resetting of the x seed - m_x = (uint)seed; - m_y = c_y; - m_z = c_z; - m_w = c_w; + x = (uint)seed; + y = Y; + z = Z; + w = W; } - /// - /// Generates a uint. Values returned are over the full range of a uint, - /// uint.MinValue to uint.MaxValue, including the min and max values. - /// - [CLSCompliant(false)] - public uint NextUInt() - { - uint t = (m_x ^ (m_x << 11)); - m_x = m_y; m_y = m_z; m_z = m_w; - return (m_w = (m_w ^ (m_w >> 19)) ^ (t ^ (t >> 8))); - } + #endregion + + #region Public Methods [System.Random functionally equivalent methods] /// - /// Generates a random int. Values returned are over the range 0 to int.MaxValue-1. - /// MaxValue is not generated to remain functionally equivalent to System.Random.Next(). - /// If you require an int from the full range, including negative values then call - /// NextUint() and cast the value to an int. + /// Generates a random int over the range 0 to int.MaxValue-1. + /// MaxValue is not generated in order to remain functionally equivalent to System.Random.Next(). + /// This does slightly eat into some of the performance gain over System.Random, but not much. + /// For better performance see: + /// + /// Call NextInt() for an int over the range 0 to int.MaxValue. + /// + /// Call NextUInt() and cast the result to an int to generate an int over the full Int32 value range + /// including negative values. /// /// - public override int Next() + public int Next() { - uint t = (m_x ^ (m_x << 11)); - m_x = m_y; m_y = m_z; m_z = m_w; - return (int)(0x7FFFFFFF & (m_w = (m_w ^ (m_w >> 19)) ^ (t ^ (t >> 8)))); + uint t = (x ^ (x << 11)); + x = y; y = z; z = w; + w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)); + + // Handle the special case where the value int.MaxValue is generated. This is outside of + // the range of permitted values, so we therefore call Next() to try again. + uint rtn = w & 0x7FFFFFFF; + if (rtn == 0x7FFFFFFF) + return Next(); + return (int)rtn; } /// /// Generates a random int over the range 0 to upperBound-1, and not including upperBound. /// - public override int Next(int maxValue) + /// + /// + public int Next(int upperBound) { - if (maxValue < 0) - throw new ArgumentOutOfRangeException("maxValue", maxValue, "maxValue must be >=0"); + if (upperBound < 0) + throw new ArgumentOutOfRangeException("upperBound", upperBound, "upperBound must be >=0"); - uint t = (m_x ^ (m_x << 11)); - m_x = m_y; m_y = m_z; m_z = m_w; + uint t = (x ^ (x << 11)); + x = y; y = z; z = w; // The explicit int cast before the first multiplication gives better performance. // See comments in NextDouble. - return (int)((c_realUnitInt * (int)(0x7FFFFFFF & (m_w = (m_w ^ (m_w >> 19)) ^ (t ^ (t >> 8))))) * maxValue); + return (int)((REAL_UNIT_INT * (int)(0x7FFFFFFF & (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8))))) * upperBound); } /// - /// Generates a random int over the range minValue to maxValue-1, and not including maxValue. - /// maxValue must be >= minValue. minValue may be negative. + /// Generates a random int over the range lowerBound to upperBound-1, and not including upperBound. + /// upperBound must be >= lowerBound. lowerBound may be negative. /// - public override int Next(int minValue, int maxValue) + /// + /// + /// + public int Next(int lowerBound, int upperBound) { - if (minValue > maxValue) - throw new ArgumentOutOfRangeException("maxValue", maxValue, "maxValue must be >=minValue"); + if (lowerBound > upperBound) + throw new ArgumentOutOfRangeException("upperBound", upperBound, "upperBound must be >=lowerBound"); - uint t = (m_x ^ (m_x << 11)); - m_x = m_y; m_y = m_z; m_z = m_w; + uint t = (x ^ (x << 11)); + x = y; y = z; z = w; // The explicit int cast before the first multiplication gives better performance. // See comments in NextDouble. - int range = maxValue - minValue; + int range = upperBound - lowerBound; if (range < 0) { // If range is <0 then an overflow has occured and must resort to using long integer arithmetic instead (slower). // We also must use all 32 bits of precision, instead of the normal 31, which again is slower. - return minValue + (int)((c_realUnitUint * (double)(m_w = (m_w ^ (m_w >> 19)) ^ (t ^ (t >> 8)))) * (double)((long)maxValue - (long)minValue)); + return lowerBound + (int)((REAL_UNIT_UINT * (double)(w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)))) * (double)((long)upperBound - (long)lowerBound)); } - // 31 bits of precision will suffice if range<=int.MaxValue. This allows us to cast to an int anf gain + // 31 bits of precision will suffice if range<=int.MaxValue. This allows us to cast to an int and gain // a little more performance. - return minValue + (int)((c_realUnitInt * (double)(int)(0x7FFFFFFF & (m_w = (m_w ^ (m_w >> 19)) ^ (t ^ (t >> 8))))) * (double)range); + return lowerBound + (int)((REAL_UNIT_INT * (double)(int)(0x7FFFFFFF & (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8))))) * (double)range); } /// /// Generates a random double. Values returned are from 0.0 up to but not including 1.0. /// /// - public override double NextDouble() + public double NextDouble() { - uint t = (m_x ^ (m_x << 11)); - m_x = m_y; m_y = m_z; m_z = m_w; + uint t = (x ^ (x << 11)); + x = y; y = z; z = w; // Here we can gain a 2x speed improvement by generating a value that can be cast to // an int instead of the more easily available uint. If we then explicitly cast to an @@ -190,117 +193,45 @@ namespace Lidgren.Network // this final cast is a lot faster than casting from a uint to a double. The extra cast // to an int is very fast (the allocated bits remain the same) and so the overall effect // of the extra cast is a significant performance improvement. - return (c_realUnitInt * (int)(0x7FFFFFFF & (m_w = (m_w ^ (m_w >> 19)) ^ (t ^ (t >> 8))))); + // + // Also note that the loss of one bit of precision is equivalent to what occurs within + // System.Random. + return (REAL_UNIT_INT * (int)(0x7FFFFFFF & (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8))))); } /// - /// Generates a random double. Values returned are from 0.0 up to but not including 1.0. + /// Generates a random single. Values returned are from 0.0 up to but not including 1.0. /// - /// - public float NextFloat() + public float NextSingle() { - uint t = (m_x ^ (m_x << 11)); - m_x = m_y; m_y = m_z; m_z = m_w; - - // Here we can gain a 2x speed improvement by generating a value that can be cast to - // an int instead of the more easily available uint. If we then explicitly cast to an - // int the compiler will then cast the int to a double to perform the multiplication, - // this final cast is a lot faster than casting from a uint to a double. The extra cast - // to an int is very fast (the allocated bits remain the same) and so the overall effect - // of the extra cast is a significant performance improvement. - return (float)(c_realUnitInt * (int)(0x7FFFFFFF & (m_w = (m_w ^ (m_w >> 19)) ^ (t ^ (t >> 8))))); - } - - /// - /// Generates a random double. Values returned are from 0.0 up to but not including roof - /// - /// - public float NextFloat(float roof) - { - uint t = (m_x ^ (m_x << 11)); - m_x = m_y; m_y = m_z; m_z = m_w; - - // Here we can gain a 2x speed improvement by generating a value that can be cast to - // an int instead of the more easily available uint. If we then explicitly cast to an - // int the compiler will then cast the int to a double to perform the multiplication, - // this final cast is a lot faster than casting from a uint to a double. The extra cast - // to an int is very fast (the allocated bits remain the same) and so the overall effect - // of the extra cast is a significant performance improvement. - float f = (float)(c_realUnitInt * (int)(0x7FFFFFFF & (m_w = (m_w ^ (m_w >> 19)) ^ (t ^ (t >> 8))))); - - return f * roof; - } - - /// - /// Generates a random double. Values returned are from min up to but not including min + variance - /// - /// - public float NextFloat(float min, float variance) - { - uint t = (m_x ^ (m_x << 11)); - m_x = m_y; m_y = m_z; m_z = m_w; - - // Here we can gain a 2x speed improvement by generating a value that can be cast to - // an int instead of the more easily available uint. If we then explicitly cast to an - // int the compiler will then cast the int to a double to perform the multiplication, - // this final cast is a lot faster than casting from a uint to a double. The extra cast - // to an int is very fast (the allocated bits remain the same) and so the overall effect - // of the extra cast is a significant performance improvement. - float f = (float)(c_realUnitInt * (int)(0x7FFFFFFF & (m_w = (m_w ^ (m_w >> 19)) ^ (t ^ (t >> 8))))); - - return min + f * variance; - } - - /// - /// If passed 0.7f it will return true 7 times out of 10 - /// - /// - public bool Chance(float percentChance) - { - uint t = (m_x ^ (m_x << 11)); - m_x = m_y; m_y = m_z; m_z = m_w; - - // Here we can gain a 2x speed improvement by generating a value that can be cast to - // an int instead of the more easily available uint. If we then explicitly cast to an - // int the compiler will then cast the int to a double to perform the multiplication, - // this final cast is a lot faster than casting from a uint to a double. The extra cast - // to an int is very fast (the allocated bits remain the same) and so the overall effect - // of the extra cast is a significant performance improvement. - double hit = (c_realUnitInt * (int)(0x7FFFFFFF & (m_w = (m_w ^ (m_w >> 19)) ^ (t ^ (t >> 8))))); - return (hit < percentChance); - } - - /// - /// Returns a System.Single larger or equal to 0 and smaller than 1.0f - gaussian distributed! - /// - public float NextGaussian() - { - return (float)((NextDouble() + NextDouble() + NextDouble()) / 3.0); + return (float)NextDouble(); } /// /// Fills the provided byte array with random bytes. - /// Increased performance is achieved by dividing and packaging bits directly from the - /// random number generator and storing them in 4 byte 'chunks'. + /// This method is functionally equivalent to System.Random.NextBytes(). /// /// - public override void NextBytes(byte[] buffer) + public void NextBytes(byte[] buffer) { // Fill up the bulk of the buffer in chunks of 4 bytes at a time. - uint x = this.m_x, y = this.m_y, z = this.m_z, w = this.m_w; + uint x = this.x, y = this.y, z = this.z, w = this.w; int i = 0; uint t; - for (; i < buffer.Length - 3; ) + for (int bound = buffer.Length - 3; i < bound; ) { - // Generate 4 bytes. + // Generate 4 bytes. + // Increased performance is achieved by generating 4 random bytes per loop. + // Also note that no mask needs to be applied to zero out the higher order bytes before + // casting because the cast ignores thos bytes. Thanks to Stefan Troschütz for pointing this out. t = (x ^ (x << 11)); x = y; y = z; z = w; w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)); - buffer[i++] = (byte)(w & 0x000000FF); - buffer[i++] = (byte)((w & 0x0000FF00) >> 8); - buffer[i++] = (byte)((w & 0x00FF0000) >> 16); - buffer[i++] = (byte)((w & 0xFF000000) >> 24); + buffer[i++] = (byte)w; + buffer[i++] = (byte)(w >> 8); + buffer[i++] = (byte)(w >> 16); + buffer[i++] = (byte)(w >> 24); } // Fill up any remaining bytes in the buffer. @@ -311,80 +242,126 @@ namespace Lidgren.Network x = y; y = z; z = w; w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)); - buffer[i++] = (byte)(w & 0x000000FF); + buffer[i++] = (byte)w; if (i < buffer.Length) { - buffer[i++] = (byte)((w & 0x0000FF00) >> 8); + buffer[i++] = (byte)(w >> 8); if (i < buffer.Length) { - buffer[i++] = (byte)((w & 0x00FF0000) >> 16); + buffer[i++] = (byte)(w >> 16); if (i < buffer.Length) { - buffer[i] = (byte)((w & 0xFF000000) >> 24); + buffer[i] = (byte)(w >> 24); } } } } - this.m_x = x; this.m_y = y; this.m_z = z; this.m_w = w; + this.x = x; this.y = y; this.z = z; this.w = w; } // /// // /// A version of NextBytes that uses a pointer to set 4 bytes of the byte buffer in one operation - // /// thus providing a nice speedup. Note that this requires the unsafe compilation flag to be specified - // /// and so is commented out by default. + // /// thus providing a nice speedup. The loop is also partially unrolled to allow out-of-order-execution, + // /// this results in about a x2 speedup on an AMD Athlon. Thus performance may vary wildly on different CPUs + // /// depending on the number of execution units available. + // /// + // /// Another significant speedup is obtained by setting the 4 bytes by indexing pDWord (e.g. pDWord[i++]=w) + // /// instead of adjusting it dereferencing it (e.g. *pDWord++=w). + // /// + // /// Note that this routine requires the unsafe compilation flag to be specified and so is commented out by default. // /// // /// // public unsafe void NextBytesUnsafe(byte[] buffer) // { - // if(buffer.Length % 4 != 0) - // throw new ArgumentException("Buffer length must be divisible by 4", "buffer"); + // if(buffer.Length % 8 != 0) + // throw new ArgumentException("Buffer length must be divisible by 8", "buffer"); // // uint x=this.x, y=this.y, z=this.z, w=this.w; - // uint t; - // + // // fixed(byte* pByte0 = buffer) // { // uint* pDWord = (uint*)pByte0; - // for(int i = 0, len = buffer.Length>>2; i < len; i++) + // for(int i=0, len=buffer.Length>>2; i < len; i+=2) // { + // uint t=(x^(x<<11)); + // x=y; y=z; z=w; + // pDWord[i] = w = (w^(w>>19))^(t^(t>>8)); + // // t=(x^(x<<11)); // x=y; y=z; z=w; - // *pDWord++ = w = (w^(w>>19))^(t^(t>>8)); + // pDWord[i+1] = w = (w^(w>>19))^(t^(t>>8)); // } // } // // this.x=x; this.y=y; this.z=z; this.w=w; // } + #endregion + + #region Public Methods [Methods not present on System.Random] + + /// + /// Generates a uint. Values returned are over the full range of a uint, + /// uint.MinValue to uint.MaxValue, inclusive. + /// + /// This is the fastest method for generating a single random number because the underlying + /// random number generator algorithm generates 32 random bits that can be cast directly to + /// a uint. + /// + [CLSCompliant(false)] + public uint NextUInt() + { + uint t = (x ^ (x << 11)); + x = y; y = z; z = w; + return (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8))); + } + + /// + /// Generates a random int over the range 0 to int.MaxValue, inclusive. + /// This method differs from Next() only in that the range is 0 to int.MaxValue + /// and not 0 to int.MaxValue-1. + /// + /// The slight difference in range means this method is slightly faster than Next() + /// but is not functionally equivalent to System.Random.Next(). + /// + /// + public int NextInt() + { + uint t = (x ^ (x << 11)); + x = y; y = z; z = w; + return (int)(0x7FFFFFFF & (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)))); + } + + // Buffer 32 bits in bitBuffer, return 1 at a time, keep track of how many have been returned // with bitBufferIdx. uint bitBuffer; - int bitBufferIdx = 32; + uint bitMask = 1; /// - /// Generates random bool. - /// Increased performance is achieved by buffering 32 random bits for - /// future calls. Thus the random number generator is only invoked once - /// in every 32 calls. + /// Generates a single random bit. + /// This method's performance is improved by generating 32 bits in one operation and storing them + /// ready for future calls. /// /// public bool NextBool() { - if (bitBufferIdx == 32) + if (bitMask == 1) { // Generate 32 more bits. - uint t = (m_x ^ (m_x << 11)); - m_x = m_y; m_y = m_z; m_z = m_w; - bitBuffer = m_w = (m_w ^ (m_w >> 19)) ^ (t ^ (t >> 8)); + uint t = (x ^ (x << 11)); + x = y; y = z; z = w; + bitBuffer = w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)); - // Reset the idx that tells us which bit to read next. - bitBufferIdx = 1; - return (bitBuffer & 0x1) == 1; + // Reset the bitMask that tells us which bit to read next. + bitMask = 0x80000000; + return (bitBuffer & bitMask) == 0; } - bitBufferIdx++; - return ((bitBuffer >>= 1) & 0x1) == 1; + return (bitBuffer & (bitMask >>= 1)) == 0; } + + #endregion } } diff --git a/Lidgren.Network/NetReceiverChannelBase.cs b/Lidgren.Network/NetReceiverChannelBase.cs new file mode 100644 index 0000000..5af6312 --- /dev/null +++ b/Lidgren.Network/NetReceiverChannelBase.cs @@ -0,0 +1,18 @@ +using System; + +namespace Lidgren.Network +{ + internal abstract class NetReceiverChannelBase + { + internal NetPeer m_peer; + internal NetConnection m_connection; + + public NetReceiverChannelBase(NetConnection connection) + { + m_connection = connection; + m_peer = connection.m_peer; + } + + internal abstract void ReceiveMessage(NetIncomingMessage msg); + } +} diff --git a/Lidgren.Network/NetReliableOrderedReceiver.cs b/Lidgren.Network/NetReliableOrderedReceiver.cs new file mode 100644 index 0000000..1c51599 --- /dev/null +++ b/Lidgren.Network/NetReliableOrderedReceiver.cs @@ -0,0 +1,87 @@ +using System; + +namespace Lidgren.Network +{ + internal sealed class NetReliableOrderedReceiver : NetReceiverChannelBase + { + private int m_windowStart; + private int m_windowSize; + private NetBitVector m_earlyReceived; + internal NetIncomingMessage[] m_withheldMessages; + + public NetReliableOrderedReceiver(NetConnection connection, int windowSize) + : base(connection) + { + m_windowSize = windowSize; + m_withheldMessages = new NetIncomingMessage[windowSize]; + m_earlyReceived = new NetBitVector(windowSize); + } + + private void AdvanceWindow() + { + m_earlyReceived.Set(m_windowStart % m_windowSize, false); + m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers; + } + + internal override void ReceiveMessage(NetIncomingMessage message) + { + int relate = NetUtility.RelativeSequenceNumber(message.m_sequenceNumber, m_windowStart); + + // ack no matter what + m_connection.QueueAck(message.m_receivedMessageType, message.m_sequenceNumber); + + if (relate == 0) + { + // Log("Received message #" + message.SequenceNumber + " right on time"); + + // + // excellent, right on time + // + m_peer.LogVerbose("Received RIGHT-ON-TIME " + message); + + AdvanceWindow(); + m_peer.ReleaseMessage(message); + + // release withheld messages + int nextSeqNr = (message.m_sequenceNumber + 1) % NetConstants.NumSequenceNumbers; + + while (m_earlyReceived[nextSeqNr % m_windowSize]) + { + message = m_withheldMessages[nextSeqNr % m_windowSize]; + NetException.Assert(message != null); + + // remove it from withheld messages + m_withheldMessages[nextSeqNr % m_windowSize] = null; + + m_peer.LogVerbose("Releasing withheld message #" + message); + + m_peer.ReleaseMessage(message); + + AdvanceWindow(); + nextSeqNr++; + } + + return; + } + + if (relate < 0) + { + m_peer.LogVerbose("Received message #" + message.m_sequenceNumber + " DROPPING DUPLICATE"); + // duplicate + return; + } + + // relate > 0 = early message + if (relate > m_windowSize) + { + // too early message! + m_peer.LogDebug("Received " + message + " TOO EARLY! Expected " + m_windowStart); + return; + } + + m_earlyReceived.Set(message.m_sequenceNumber % m_windowSize, true); + m_peer.LogVerbose("Received " + message + " WITHHOLDING, waiting for " + m_windowStart); + m_withheldMessages[message.m_sequenceNumber % m_windowSize] = message; + } + } +} diff --git a/Lidgren.Network/NetReliableSenderChannel.cs b/Lidgren.Network/NetReliableSenderChannel.cs new file mode 100644 index 0000000..69206d2 --- /dev/null +++ b/Lidgren.Network/NetReliableSenderChannel.cs @@ -0,0 +1,236 @@ +using System; +using System.Threading; + +namespace Lidgren.Network +{ + /// + /// Sender part of Selective repeat ARQ for a particular NetChannel + /// + internal sealed class NetReliableSenderChannel : NetSenderChannelBase + { + private NetConnection m_connection; + private int m_windowStart; + private int m_windowSize; + private int m_sendStart; + + private NetBitVector m_receivedAcks; + internal NetStoredReliableMessage[] m_storedMessages; + + internal override int WindowSize { get { return m_windowSize; } } + + internal NetReliableSenderChannel(NetConnection connection, int windowSize) + { + m_connection = connection; + m_windowSize = windowSize; + m_windowStart = 0; + m_sendStart = 0; + m_receivedAcks = new NetBitVector(NetConstants.NumSequenceNumbers); + m_storedMessages = new NetStoredReliableMessage[m_windowSize]; + m_queuedSends = new NetQueue(8); + } + + internal override int GetAllowedSends() + { + int retval = m_windowSize - ((m_sendStart + NetConstants.NumSequenceNumbers) - m_windowStart) % NetConstants.NumSequenceNumbers; + NetException.Assert(retval >= 0 && retval <= m_windowSize); + return retval; + } + + internal override void Reset() + { + m_receivedAcks.Clear(); + for (int i = 0; i < m_storedMessages.Length; i++) + m_storedMessages[i].Reset(); + m_queuedSends.Clear(); + m_windowStart = 0; + m_sendStart = 0; + } + + internal override NetSendResult Enqueue(NetOutgoingMessage message) + { + m_queuedSends.Enqueue(message); + + int queueLen = m_queuedSends.Count; + int left = m_windowSize - ((m_sendStart + NetConstants.NumSequenceNumbers) - m_windowStart) % NetConstants.NumSequenceNumbers; + if (queueLen <= left) + return NetSendResult.Sent; + return NetSendResult.Queued; + } + + // call this regularely + internal override void SendQueuedMessages(float now) + { + // resends + float resendDelay = m_connection.GetResendDelay(); + for (int i = 0; i < m_storedMessages.Length; i++) + { + NetOutgoingMessage om = m_storedMessages[i].Message; + if (om == null) + continue; + + float t = m_storedMessages[i].LastSent; + if (t > 0 && (now - t) > resendDelay) + { + // deduce sequence number + int startSlot = m_windowStart % m_windowSize; + int seqNr = m_windowStart; + while (startSlot != i) + { + startSlot--; + if (startSlot < 0) + startSlot = m_windowSize - 1; + seqNr--; + } + + m_connection.m_peer.LogVerbose("Resending due to delay #" + seqNr + " " + om.ToString()); + m_connection.m_statistics.MessageResent(); + + m_connection.QueueSendMessage(om, seqNr); + + m_storedMessages[i].LastSent = now; + m_storedMessages[i].NumSent++; + } + } + + int num = GetAllowedSends(); + if (num < 1) + return; + + // queued sends + while (m_queuedSends.Count > 0 && num > 0) + { + NetOutgoingMessage om; + if (m_queuedSends.TryDequeue(out om)) + ExecuteSend(now, om); + num--; + NetException.Assert(num == GetAllowedSends()); + } + } + + private void ExecuteSend(float now, NetOutgoingMessage message) + { + int seqNr = m_sendStart; + m_sendStart = (m_sendStart + 1) % NetConstants.NumSequenceNumbers; + + m_connection.QueueSendMessage(message, seqNr); + + int storeIndex = seqNr % m_windowSize; + NetException.Assert(m_storedMessages[storeIndex].Message == null); + + m_storedMessages[storeIndex].NumSent++; + m_storedMessages[storeIndex].Message = message; + m_storedMessages[storeIndex].LastSent = now; + + return; + } + + private void DestoreMessage(int storeIndex) + { + NetOutgoingMessage storedMessage = m_storedMessages[storeIndex].Message; + NetException.Assert(storedMessage != null); + + Interlocked.Decrement(ref storedMessage.m_recyclingCount); + if (storedMessage.m_recyclingCount <= 0) + m_connection.m_peer.Recycle(storedMessage); + + m_storedMessages[storeIndex] = new NetStoredReliableMessage(); + } + + // remoteWindowStart is remote expected sequence number; everything below this has arrived properly + // seqNr is the actual nr received + internal override void ReceiveAcknowledge(float now, int seqNr) + { + // late (dupe), on time or early ack? + int relate = NetUtility.RelativeSequenceNumber(seqNr, m_windowStart); + + if (relate < 0) + { + //m_connection.m_peer.LogDebug("Received late/dupe ack for #" + seqNr); + return; // late/duplicate ack + } + + if (relate == 0) + { + //m_connection.m_peer.LogDebug("Received right-on-time ack for #" + seqNr); + + // ack arrived right on time + NetException.Assert(seqNr == m_windowStart); + + m_receivedAcks[m_windowStart] = false; + DestoreMessage(m_windowStart % m_windowSize); + m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers; + + // advance window if we already have early acks + while (m_receivedAcks[m_windowStart]) + { + //m_connection.m_peer.LogDebug("Using early ack for #" + m_windowStart + "..."); + m_receivedAcks[m_windowStart] = false; + NetException.Assert(m_storedMessages[m_windowStart % m_windowSize].Message == null); // should already be destored + m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers; + //m_connection.m_peer.LogDebug("Advancing window to #" + m_windowStart); + } + + return; + } + + // + // early ack... (if it has been sent!) + // + // If it has been sent either the m_windowStart message was lost + // ... or the ack for that message was lost + // + + //m_connection.m_peer.LogDebug("Received early ack for #" + seqNr); + + int sendRelate = NetUtility.RelativeSequenceNumber(seqNr, m_sendStart); + if (sendRelate <= 0) + { + // yes, we've sent this message - it's an early (but valid) ack + if (m_receivedAcks[seqNr]) + { + // we've already destored/been acked for this message + } + else + { + DestoreMessage(seqNr % m_windowSize); + m_receivedAcks[seqNr] = true; + } + } + else if (sendRelate > 0) + { + // uh... we haven't sent this message yet? Weird, dupe or error... + return; + } + + // Ok, lets resend all missing acks + int rnr = seqNr; + do + { + rnr--; + if (rnr < 0) + rnr = NetConstants.NumSequenceNumbers - 1; + + if (m_receivedAcks[rnr]) + { + // m_connection.m_peer.LogDebug("Not resending #" + rnr + " (since we got ack)"); + } + else + { + int slot = rnr % m_windowSize; + NetException.Assert(m_storedMessages[slot].Message != null); + if (m_storedMessages[slot].NumSent == 1) + { + // just sent once; resend immediately since we found gap in ack sequence + NetOutgoingMessage rmsg = m_storedMessages[slot].Message; + m_connection.m_peer.LogVerbose("Resending #" + rnr + " (" + rmsg + ")"); + m_storedMessages[slot].LastSent = now; + m_storedMessages[slot].NumSent++; + m_connection.m_statistics.MessageResent(); + m_connection.QueueSendMessage(rmsg, rnr); + } + } + + } while (rnr != m_windowStart); + } + } +} diff --git a/Lidgren.Network/NetReliableSequencedReceiver.cs b/Lidgren.Network/NetReliableSequencedReceiver.cs new file mode 100644 index 0000000..c08d8ab --- /dev/null +++ b/Lidgren.Network/NetReliableSequencedReceiver.cs @@ -0,0 +1,63 @@ +using System; + +namespace Lidgren.Network +{ + internal sealed class NetReliableSequencedReceiver : NetReceiverChannelBase + { + private int m_windowStart; + private int m_windowSize; + + public NetReliableSequencedReceiver(NetConnection connection, int windowSize) + : base(connection) + { + m_windowSize = windowSize; + } + + private void AdvanceWindow() + { + m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers; + } + + internal override void ReceiveMessage(NetIncomingMessage message) + { + int nr = message.m_sequenceNumber; + + int relate = NetUtility.RelativeSequenceNumber(nr, m_windowStart); + + // ack no matter what + m_connection.QueueAck(message.m_receivedMessageType, nr); + + if (relate == 0) + { + // Log("Received message #" + message.SequenceNumber + " right on time"); + + // + // excellent, right on time + // + + AdvanceWindow(); + m_peer.ReleaseMessage(message); + return; + } + + if (relate < 0) + { + m_peer.LogVerbose("Received message #" + message.m_sequenceNumber + " DROPPING LATE or DUPE"); + return; + } + + // relate > 0 = early message + if (relate > m_windowSize) + { + // too early message! + m_peer.LogDebug("Received " + message + " TOO EARLY! Expected " + m_windowStart); + return; + } + + // ok + m_windowStart = (m_windowStart + relate) % NetConstants.NumSequenceNumbers; + m_peer.ReleaseMessage(message); + return; + } + } +} diff --git a/Lidgren.Network/NetReliableUnorderedReceiver.cs b/Lidgren.Network/NetReliableUnorderedReceiver.cs new file mode 100644 index 0000000..5d3a2d8 --- /dev/null +++ b/Lidgren.Network/NetReliableUnorderedReceiver.cs @@ -0,0 +1,87 @@ +using System; + +namespace Lidgren.Network +{ + internal sealed class NetReliableUnorderedReceiver : NetReceiverChannelBase + { + private int m_windowStart; + private int m_windowSize; + private NetBitVector m_earlyReceived; + + public NetReliableUnorderedReceiver(NetConnection connection, int windowSize) + : base(connection) + { + m_windowSize = windowSize; + m_earlyReceived = new NetBitVector(windowSize); + } + + private void AdvanceWindow() + { + m_earlyReceived.Set(m_windowStart % m_windowSize, false); + m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers; + } + + internal override void ReceiveMessage(NetIncomingMessage message) + { + int relate = NetUtility.RelativeSequenceNumber(message.m_sequenceNumber, m_windowStart); + + // ack no matter what + m_connection.QueueAck(message.m_receivedMessageType, message.m_sequenceNumber); + + if (relate == 0) + { + // Log("Received message #" + message.SequenceNumber + " right on time"); + + // + // excellent, right on time + // + m_peer.LogVerbose("Received RIGHT-ON-TIME " + message); + + AdvanceWindow(); + m_peer.ReleaseMessage(message); + + // release withheld messages + int nextSeqNr = (message.m_sequenceNumber + 1) % NetConstants.NumSequenceNumbers; + + while (m_earlyReceived[nextSeqNr % m_windowSize]) + { + //message = m_withheldMessages[nextSeqNr % m_windowSize]; + //NetException.Assert(message != null); + + // remove it from withheld messages + //m_withheldMessages[nextSeqNr % m_windowSize] = null; + + //m_peer.LogVerbose("Releasing withheld message #" + message); + + //m_peer.ReleaseMessage(message); + + AdvanceWindow(); + nextSeqNr++; + } + + return; + } + + if (relate < 0) + { + // duplicate + m_peer.LogVerbose("Received message #" + message.m_sequenceNumber + " DROPPING DUPLICATE"); + return; + } + + // relate > 0 = early message + if (relate > m_windowSize) + { + // too early message! + m_peer.LogDebug("Received " + message + " TOO EARLY! Expected " + m_windowStart); + return; + } + + m_earlyReceived.Set(message.m_sequenceNumber % m_windowSize, true); + //m_peer.LogVerbose("Received " + message + " WITHHOLDING, waiting for " + m_windowStart); + //m_withheldMessages[message.m_sequenceNumber % m_windowSize] = message; + + m_peer.ReleaseMessage(message); + } + } +} diff --git a/Lidgren.Network/NetSendResult.cs b/Lidgren.Network/NetSendResult.cs new file mode 100644 index 0000000..e63d247 --- /dev/null +++ b/Lidgren.Network/NetSendResult.cs @@ -0,0 +1,30 @@ +using System; + +namespace Lidgren.Network +{ + /// + /// Result of a SendMessage call + /// + public enum NetSendResult + { + /// + /// Message failed to enqueue; for example if there's no connection in place + /// + Failed = 0, + + /// + /// Message was immediately sent + /// + Sent = 1, + + /// + /// Message was queued for delivery + /// + Queued = 2, + + /// + /// Message was dropped immediately since too many message were queued + /// + Dropped = 3 + } +} diff --git a/Lidgren.Network/NetSenderChannelBase.cs b/Lidgren.Network/NetSenderChannelBase.cs new file mode 100644 index 0000000..b03e362 --- /dev/null +++ b/Lidgren.Network/NetSenderChannelBase.cs @@ -0,0 +1,19 @@ +using System; + +namespace Lidgren.Network +{ + internal abstract class NetSenderChannelBase + { + // access this directly to queue things in this channel + internal NetQueue m_queuedSends; + + internal abstract int WindowSize { get; } + + internal abstract int GetAllowedSends(); + + internal abstract NetSendResult Enqueue(NetOutgoingMessage message); + internal abstract void SendQueuedMessages(float now); + internal abstract void Reset(); + internal abstract void ReceiveAcknowledge(float now, int sequenceNumber); + } +} diff --git a/Lidgren.Network/NetSending.cs b/Lidgren.Network/NetSending.cs deleted file mode 100644 index 0d3b9c1..0000000 --- a/Lidgren.Network/NetSending.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net; -using System.Diagnostics; - -namespace Lidgren.Network -{ - [DebuggerDisplay("MessageType={MessageType} SequenceNumber={SequenceNumber} NumSends={NumSends}")] - internal sealed class NetSending - { - public NetOutgoingMessage Message; - public IPEndPoint Recipient; - public NetMessageType MessageType; - public ushort SequenceNumber; - public double NextResend; - public int NumSends; // how many times has this sending been sent - - public int FragmentGroupId; - public int FragmentNumber; - public int FragmentTotalCount; - - public NetSending(NetOutgoingMessage msg, NetMessageType tp, ushort sequenceNumber) - { - Message = msg; - MessageType = tp; - SequenceNumber = sequenceNumber; - } - - internal void SetNextResend(NetConnection conn) - { - float baseDelay; - switch(NumSends) - { - case 0: baseDelay = 0.025f; break; - case 1: baseDelay = 0.05f; break; - case 2: baseDelay = 0.15f; break; - case 3: baseDelay = 0.3f; break; - default: - baseDelay = (float)(NumSends - 3); // 4: 1 second, 5: 2 seconds, 6: 3 seconds etc - break; - } - - float rttMultiplier = 1.15f + (0.15f * NumSends); - - float totalDelay = baseDelay + (conn.AverageRoundtripTime * rttMultiplier); - - NextResend = NetTime.Now + totalDelay; - } - - public override string ToString() - { - return "[NetSending " + MessageType + "#" + SequenceNumber + " NumSends: " + NumSends + "]"; - } - } -} diff --git a/Lidgren.Network/NetServer.cs b/Lidgren.Network/NetServer.cs index 9098eb4..7162c15 100644 --- a/Lidgren.Network/NetServer.cs +++ b/Lidgren.Network/NetServer.cs @@ -1,41 +1,16 @@ -/* Copyright (c) 2010 Michael Lidgren - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software -and associated documentation files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom -the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ -using System; +using System; namespace Lidgren.Network { + /// + /// Specialized version of NetPeer used for "server" peers + /// public class NetServer : NetPeer { public NetServer(NetPeerConfiguration config) : base(config) { - // force this to true config.AcceptIncomingConnections = true; } - - public void Disconnect(NetConnection connection, string byeMessage) - { - if (connection == null) - throw new ArgumentNullException("connection"); - - connection.Disconnect(byeMessage); - } } } diff --git a/Lidgren.Network/NetStoredReliableMessage.cs b/Lidgren.Network/NetStoredReliableMessage.cs new file mode 100644 index 0000000..b98bf5e --- /dev/null +++ b/Lidgren.Network/NetStoredReliableMessage.cs @@ -0,0 +1,18 @@ +using System; + +namespace Lidgren.Network +{ + internal struct NetStoredReliableMessage + { + public int NumSent; + public float LastSent; + public NetOutgoingMessage Message; + + public void Reset() + { + NumSent = 0; + LastSent = 0; + Message = null; + } + } +} diff --git a/Lidgren.Network/NetTime.cs b/Lidgren.Network/NetTime.cs index 4fd78fb..986f9c8 100644 --- a/Lidgren.Network/NetTime.cs +++ b/Lidgren.Network/NetTime.cs @@ -45,10 +45,6 @@ namespace Lidgren.Network /// public static double Now { get { return (double)Environment.TickCount / 1000.0; } } #endif - public static double GetRemoteNow(NetConnection conn) - { - return Now - conn.m_remoteToLocalNetTime; - } public static string ToReadable(double seconds) { diff --git a/Lidgren.Network/NetTuple.cs b/Lidgren.Network/NetTuple.cs new file mode 100644 index 0000000..70973a8 --- /dev/null +++ b/Lidgren.Network/NetTuple.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Lidgren.Network +{ + // replace with BCL 4.0 Tuple<> when appropriate + internal struct NetTuple + { + public A Item1; + public B Item2; + + public NetTuple(A item1, B item2) + { + Item1 = item1; + Item2 = item2; + } + } +} diff --git a/Lidgren.Network/NetUnreliableSenderChannel.cs b/Lidgren.Network/NetUnreliableSenderChannel.cs new file mode 100644 index 0000000..7d54c23 --- /dev/null +++ b/Lidgren.Network/NetUnreliableSenderChannel.cs @@ -0,0 +1,125 @@ +using System; +using System.Threading; + +namespace Lidgren.Network +{ + /// + /// Sender part of Selective repeat ARQ for a particular NetChannel + /// + internal sealed class NetUnreliableSenderChannel : NetSenderChannelBase + { + private NetConnection m_connection; + private int m_windowStart; + private int m_windowSize; + private int m_sendStart; + + private NetBitVector m_receivedAcks; + + internal override int WindowSize { get { return m_windowSize; } } + + internal NetUnreliableSenderChannel(NetConnection connection, int windowSize) + { + m_connection = connection; + m_windowSize = windowSize; + m_windowStart = 0; + m_sendStart = 0; + m_receivedAcks = new NetBitVector(NetConstants.NumSequenceNumbers); + m_queuedSends = new NetQueue(8); + } + + internal override int GetAllowedSends() + { + int retval = m_windowSize - ((m_sendStart + NetConstants.NumSequenceNumbers) - m_windowStart) % m_windowSize; + NetException.Assert(retval >= 0 && retval <= m_windowSize); + return retval; + } + + internal override void Reset() + { + m_receivedAcks.Clear(); + m_queuedSends.Clear(); + m_windowStart = 0; + m_sendStart = 0; + } + + internal override NetSendResult Enqueue(NetOutgoingMessage message) + { + int queueLen = m_queuedSends.Count + 1; + int left = m_windowSize - ((m_sendStart + NetConstants.NumSequenceNumbers) - m_windowStart) % NetConstants.NumSequenceNumbers; + if (queueLen > left) + return NetSendResult.Dropped; + + m_queuedSends.Enqueue(message); + return NetSendResult.Sent; + } + + // call this regularely + internal override void SendQueuedMessages(float now) + { + int num = GetAllowedSends(); + if (num < 1) + return; + + // queued sends + while (m_queuedSends.Count > 0 && num > 0) + { + NetOutgoingMessage om; + if (m_queuedSends.TryDequeue(out om)) + ExecuteSend(now, om); + num--; + } + } + + private void ExecuteSend(float now, NetOutgoingMessage message) + { + m_connection.m_peer.VerifyNetworkThread(); + + int seqNr = m_sendStart; + m_sendStart = (m_sendStart + 1) % NetConstants.NumSequenceNumbers; + + m_connection.QueueSendMessage(message, seqNr); + + Interlocked.Decrement(ref message.m_recyclingCount); + if (message.m_recyclingCount <= 0) + m_connection.m_peer.Recycle(message); + + return; + } + + // remoteWindowStart is remote expected sequence number; everything below this has arrived properly + // seqNr is the actual nr received + internal override void ReceiveAcknowledge(float now, int seqNr) + { + // late (dupe), on time or early ack? + int relate = NetUtility.RelativeSequenceNumber(seqNr, m_windowStart); + + if (relate < 0) + { + //m_connection.m_peer.LogDebug("Received late/dupe ack for #" + seqNr); + return; // late/duplicate ack + } + + if (relate == 0) + { + //m_connection.m_peer.LogDebug("Received right-on-time ack for #" + seqNr); + + // ack arrived right on time + NetException.Assert(seqNr == m_windowStart); + + m_receivedAcks[m_windowStart] = false; + m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers; + + return; + } + + // Advance window to this position + m_receivedAcks[seqNr] = true; + + while (m_windowStart != seqNr) + { + m_receivedAcks[m_windowStart] = false; + m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers; + } + } + } +} diff --git a/Lidgren.Network/NetUnreliableSequencedReceiver.cs b/Lidgren.Network/NetUnreliableSequencedReceiver.cs new file mode 100644 index 0000000..6c9e968 --- /dev/null +++ b/Lidgren.Network/NetUnreliableSequencedReceiver.cs @@ -0,0 +1,29 @@ +using System; + +namespace Lidgren.Network +{ + internal sealed class NetUnreliableSequencedReceiver : NetReceiverChannelBase + { + private int m_lastReceivedSequenceNumber; + + public NetUnreliableSequencedReceiver(NetConnection connection) + : base(connection) + { + } + + internal override void ReceiveMessage(NetIncomingMessage msg) + { + int nr = msg.m_sequenceNumber; + + // ack no matter what + m_connection.QueueAck(msg.m_receivedMessageType, nr); + + int relate = NetUtility.RelativeSequenceNumber(nr, m_lastReceivedSequenceNumber); + if (relate < 0) + return; // drop if late + + m_lastReceivedSequenceNumber = nr; + m_peer.ReleaseMessage(msg); + } + } +} diff --git a/Lidgren.Network/NetUnreliableUnorderedReceiver.cs b/Lidgren.Network/NetUnreliableUnorderedReceiver.cs new file mode 100644 index 0000000..9d15e55 --- /dev/null +++ b/Lidgren.Network/NetUnreliableUnorderedReceiver.cs @@ -0,0 +1,20 @@ +using System; + +namespace Lidgren.Network +{ + internal sealed class NetUnreliableUnorderedReceiver : NetReceiverChannelBase + { + public NetUnreliableUnorderedReceiver(NetConnection connection) + : base(connection) + { + } + + internal override void ReceiveMessage(NetIncomingMessage msg) + { + // ack no matter what + m_connection.QueueAck(msg.m_receivedMessageType, msg.m_sequenceNumber); + + m_peer.ReleaseMessage(msg); + } + } +} diff --git a/Lidgren.Network/NetUtility.cs b/Lidgren.Network/NetUtility.cs index 1a453ca..386ef67 100644 --- a/Lidgren.Network/NetUtility.cs +++ b/Lidgren.Network/NetUtility.cs @@ -144,7 +144,7 @@ namespace Lidgren.Network } return new string(c); } - + /// /// Gets my local IP address (not necessarily external) and subnet mask /// @@ -261,5 +261,61 @@ namespace Lidgren.Network retval[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16); return retval; } + + public static string ToHumanReadable(long bytes) + { + if (bytes < 4000) // 1-4 kb is printed in bytes + return bytes + " bytes"; + if (bytes < 1000 * 1000) // 4-999 kb is printed in kb + return Math.Round(((double)bytes / 1000.0), 2) + " kilobytes"; + return Math.Round(((double)bytes / (1000.0 * 1000.0)), 2) + " megabytes"; // else megabytes + } + + internal static int RelativeSequenceNumber(int nr, int expected) + { + int retval = ((nr + NetConstants.NumSequenceNumbers) - expected) % NetConstants.NumSequenceNumbers; + if (retval > (NetConstants.NumSequenceNumbers / 2)) + retval -= NetConstants.NumSequenceNumbers; + return retval; + } + + // shell sort + internal static void SortMembersList(System.Reflection.MemberInfo[] list) + { + int h; + int j; + System.Reflection.MemberInfo tmp; + + h = 1; + while (h * 3 + 1 <= list.Length) + h = 3 * h + 1; + + while (h > 0) + { + for (int i = h - 1; i < list.Length; i++) + { + tmp = list[i]; + j = i; + while (true) + { + if (j >= h) + { + if (string.Compare(list[j - h].Name, tmp.Name, StringComparison.InvariantCulture) > 0) + { + list[j] = list[j - h]; + j -= h; + } + else + break; + } + else + break; + } + + list[j] = tmp; + } + h /= 3; + } + } } -} +} \ No newline at end of file diff --git a/Lidgren.Network/SenderChannelBase.cs b/Lidgren.Network/SenderChannelBase.cs new file mode 100644 index 0000000..c7aeee5 --- /dev/null +++ b/Lidgren.Network/SenderChannelBase.cs @@ -0,0 +1,11 @@ +using System; + +namespace Lidgren.Network +{ + internal abstract class SenderChannelBase + { + internal abstract NetSendResult Send(float now, NetOutgoingMessage message); + internal abstract void SendQueuedMessages(float now); + internal abstract void Reset(); + } +} diff --git a/Samples/BarebonesClient/BarebonesClient.csproj b/Samples/BarebonesClient/BarebonesClient.csproj deleted file mode 100644 index 7bb0178..0000000 --- a/Samples/BarebonesClient/BarebonesClient.csproj +++ /dev/null @@ -1,58 +0,0 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {BC0CBAEE-70FE-4B1E-A2FA-BCC731F1E48F} - Exe - Properties - BarebonesClient - BarebonesClient - v3.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - 3.5 - - - - - - - - - - {FA245447-5F23-4AA1-BD5F-8D2DDF33CFBD} - Lidgren.Network - - - - - \ No newline at end of file diff --git a/Samples/BarebonesClient/Program.cs b/Samples/BarebonesClient/Program.cs deleted file mode 100644 index f601283..0000000 --- a/Samples/BarebonesClient/Program.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.Text; -using System.Threading; - -using Lidgren.Network; - -namespace BarebonesClient -{ - class Program - { - static void Main(string[] args) - { - NetPeerConfiguration config = new NetPeerConfiguration("barebones"); -#if DEBUG - config.SimulatedLoss = 0.1f; -#endif - config.EnableMessageType(NetIncomingMessageType.VerboseDebugMessage); - NetClient client = new NetClient(config); - client.Start(); - - Thread.Sleep(2000); - - client.Connect("localhost", 14242); - - while (Console.KeyAvailable == false || Console.ReadKey().Key != ConsoleKey.Escape) - { - NetIncomingMessage inc; - while ((inc = client.ReadMessage()) != null) - { - switch (inc.MessageType) - { - case NetIncomingMessageType.StatusChanged: - NetConnectionStatus status = (NetConnectionStatus)inc.ReadByte(); - string reason = inc.ReadString(); - Console.WriteLine("New status: " + status + " (" + reason + ")"); - if (status == NetConnectionStatus.Connected) - { - // - // We're connected - send stuff - // - NetOutgoingMessage om = client.CreateMessage(); - - // temporary code to verify issue with large messages - StringBuilder bdr = new StringBuilder(); - for (int i = 0; i < 400; i++) - bdr.Append("Hallonsmurf" + i.ToString()); - om.Write(bdr.ToString()); - - client.SendMessage(om, NetDeliveryMethod.ReliableOrdered); - } - break; - case NetIncomingMessageType.DebugMessage: - case NetIncomingMessageType.VerboseDebugMessage: - case NetIncomingMessageType.WarningMessage: - case NetIncomingMessageType.ErrorMessage: - Console.WriteLine(inc.ReadString()); - break; - case NetIncomingMessageType.UnconnectedData: - Console.WriteLine("Received unconnected data from " + inc.SenderEndpoint + ", conn is " + inc.SenderConnection); - break; - case NetIncomingMessageType.Data: - Console.WriteLine("Received " + inc.LengthBytes + " bytes of data from " + inc.SenderConnection + ", endpoint is " + inc.SenderEndpoint); - break; - } - } - Thread.Sleep(1); - } - Console.WriteLine("Application exiting"); - while (true) ; - } - } -} diff --git a/Samples/BarebonesClient/Properties/AssemblyInfo.cs b/Samples/BarebonesClient/Properties/AssemblyInfo.cs deleted file mode 100644 index 942b9e4..0000000 --- a/Samples/BarebonesClient/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("BarebonesClient")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("BarebonesClient")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("30270c13-84c7-4b20-971f-44adbd45635b")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Samples/BarebonesServer/BarebonesServer.csproj b/Samples/BarebonesServer/BarebonesServer.csproj deleted file mode 100644 index f70e5de..0000000 --- a/Samples/BarebonesServer/BarebonesServer.csproj +++ /dev/null @@ -1,58 +0,0 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {438173C5-8E95-4AE1-AAAB-5C1009F05302} - Exe - Properties - BarebonesServer - BarebonesServer - v3.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - 3.5 - - - - - - - - - - {FA245447-5F23-4AA1-BD5F-8D2DDF33CFBD} - Lidgren.Network - - - - - \ No newline at end of file diff --git a/Samples/BarebonesServer/Program.cs b/Samples/BarebonesServer/Program.cs deleted file mode 100644 index 42e8231..0000000 --- a/Samples/BarebonesServer/Program.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Text; -using System.Threading; - -using Lidgren.Network; - -namespace BarebonesServer -{ - class Program - { - static void Main(string[] args) - { - NetPeerConfiguration config = new NetPeerConfiguration("barebones"); - config.Port = 14242; -#if DEBUG - config.SimulatedLoss = 0.1f; -#endif - config.EnableMessageType(NetIncomingMessageType.VerboseDebugMessage); - NetServer server = new NetServer(config); - server.Start(); - - NetIncomingMessage inc; - while (Console.KeyAvailable == false || Console.ReadKey().Key != ConsoleKey.Escape) - { - while ((inc = server.ReadMessage()) != null) - { - switch (inc.MessageType) - { - case NetIncomingMessageType.DebugMessage: - case NetIncomingMessageType.VerboseDebugMessage: - case NetIncomingMessageType.WarningMessage: - case NetIncomingMessageType.ErrorMessage: - Console.WriteLine(inc.ReadString()); - break; - case NetIncomingMessageType.StatusChanged: - NetConnectionStatus status = (NetConnectionStatus)inc.ReadByte(); - string reason = inc.ReadString(); - Console.WriteLine("New status: " + status + " (" + reason + ")"); - break; - case NetIncomingMessageType.UnconnectedData: - Console.WriteLine("Received unconnected data from " + inc.SenderEndpoint + ", conn is " + inc.SenderConnection); - break; - case NetIncomingMessageType.Data: - Console.WriteLine("Received " + inc.LengthBytes + " bytes of data from " + inc.SenderConnection + ", endpoint is " + inc.SenderEndpoint); - - // temporary code to verify issue with large messages - StringBuilder bdr = new StringBuilder(); - for (int i = 0; i < 400; i++) - bdr.Append("Hallonsmurf" + i.ToString()); - - string str = inc.ReadString(); - - Console.WriteLine("Compare gives: " + str.CompareTo(bdr.ToString())); - - break; - } - } - - Thread.Sleep(1); - } - - Console.WriteLine("Application exiting"); - while (true) ; - } - } -} diff --git a/Samples/BarebonesServer/Properties/AssemblyInfo.cs b/Samples/BarebonesServer/Properties/AssemblyInfo.cs deleted file mode 100644 index f7ef425..0000000 --- a/Samples/BarebonesServer/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("BarebonesServer")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("BarebonesServer")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("f0faed82-6c17-41dc-a45e-c9534a29eff8")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Samples/Chat/Chat.sln b/Samples/Chat/Chat.sln new file mode 100644 index 0000000..29ef451 --- /dev/null +++ b/Samples/Chat/Chat.sln @@ -0,0 +1,57 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamplesCommon", "..\SamplesCommon\SamplesCommon.csproj", "{773069DA-B66E-4667-ADCB-0D215AD8CF3E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lidgren.Network", "..\..\Lidgren.Network\Lidgren.Network.csproj", "{AE483C29-042E-4226-BA52-D247CE7676DA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatServer", "ChatServer\ChatServer.csproj", "{C5473E52-7601-48CA-BFEB-1AB012F3D4BF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatClient", "ChatClient\ChatClient.csproj", "{B166F0BF-FB75-41F1-A527-B289BDF0FA0C}" +EndProject +Global + GlobalSection(SourceCodeControl) = preSolution + SccNumberOfProjects = 5 + SccProjectName0 = Perforce\u0020Project + SccLocalPath0 = ..\\.. + SccProvider0 = MSSCCI:Perforce\u0020SCM + SccProjectFilePathRelativizedFromConnection0 = Samples\\Chat\\ + SccProjectUniqueName1 = ..\\..\\Lidgren.Network\\Lidgren.Network.csproj + SccLocalPath1 = ..\\.. + SccProjectFilePathRelativizedFromConnection1 = Lidgren.Network\\ + SccProjectUniqueName2 = ChatClient\\ChatClient.csproj + SccLocalPath2 = ..\\.. + SccProjectFilePathRelativizedFromConnection2 = Samples\\Chat\\ChatClient\\ + SccProjectUniqueName3 = ChatServer\\ChatServer.csproj + SccLocalPath3 = ..\\.. + SccProjectFilePathRelativizedFromConnection3 = Samples\\Chat\\ChatServer\\ + SccProjectUniqueName4 = ..\\SamplesCommon\\SamplesCommon.csproj + SccLocalPath4 = ..\\.. + SccProjectFilePathRelativizedFromConnection4 = Samples\\SamplesCommon\\ + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {773069DA-B66E-4667-ADCB-0D215AD8CF3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {773069DA-B66E-4667-ADCB-0D215AD8CF3E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {773069DA-B66E-4667-ADCB-0D215AD8CF3E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {773069DA-B66E-4667-ADCB-0D215AD8CF3E}.Release|Any CPU.Build.0 = Release|Any CPU + {AE483C29-042E-4226-BA52-D247CE7676DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AE483C29-042E-4226-BA52-D247CE7676DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AE483C29-042E-4226-BA52-D247CE7676DA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AE483C29-042E-4226-BA52-D247CE7676DA}.Release|Any CPU.Build.0 = Release|Any CPU + {C5473E52-7601-48CA-BFEB-1AB012F3D4BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C5473E52-7601-48CA-BFEB-1AB012F3D4BF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C5473E52-7601-48CA-BFEB-1AB012F3D4BF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C5473E52-7601-48CA-BFEB-1AB012F3D4BF}.Release|Any CPU.Build.0 = Release|Any CPU + {B166F0BF-FB75-41F1-A527-B289BDF0FA0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B166F0BF-FB75-41F1-A527-B289BDF0FA0C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B166F0BF-FB75-41F1-A527-B289BDF0FA0C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B166F0BF-FB75-41F1-A527-B289BDF0FA0C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/ChatClient/ChatClient.csproj b/Samples/Chat/ChatClient/ChatClient.csproj similarity index 86% rename from Samples/ChatClient/ChatClient.csproj rename to Samples/Chat/ChatClient/ChatClient.csproj index ede65f6..d5132d9 100644 --- a/Samples/ChatClient/ChatClient.csproj +++ b/Samples/Chat/ChatClient/ChatClient.csproj @@ -5,13 +5,17 @@ AnyCPU 9.0.21022 2.0 - {321F68AE-7F97-415E-A3F9-7C477EFF95EE} + {B166F0BF-FB75-41F1-A527-B289BDF0FA0C} WinExe Properties ChatClient ChatClient v3.5 512 + SAK + SAK + SAK + SAK true @@ -35,11 +39,8 @@ 3.5 - - - @@ -74,11 +75,11 @@ - - {FA245447-5F23-4AA1-BD5F-8D2DDF33CFBD} + + {AE483C29-042E-4226-BA52-D247CE7676DA} Lidgren.Network - + {773069DA-B66E-4667-ADCB-0D215AD8CF3E} SamplesCommon diff --git a/Samples/ChatClient/Form1.Designer.cs b/Samples/Chat/ChatClient/Form1.Designer.cs similarity index 52% rename from Samples/ChatClient/Form1.Designer.cs rename to Samples/Chat/ChatClient/Form1.Designer.cs index 05e9b68..4e594c1 100644 --- a/Samples/ChatClient/Form1.Designer.cs +++ b/Samples/Chat/ChatClient/Form1.Designer.cs @@ -29,9 +29,12 @@ private void InitializeComponent() { this.richTextBox1 = new System.Windows.Forms.RichTextBox(); - this.textBox1 = new System.Windows.Forms.TextBox(); this.button1 = new System.Windows.Forms.Button(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.textBox3 = new System.Windows.Forms.TextBox(); this.button2 = new System.Windows.Forms.Button(); + this.button3 = new System.Windows.Forms.Button(); this.SuspendLayout(); // // richTextBox1 @@ -39,51 +42,87 @@ this.richTextBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.richTextBox1.Location = new System.Drawing.Point(12, 12); + this.richTextBox1.Location = new System.Drawing.Point(12, 40); this.richTextBox1.Name = "richTextBox1"; - this.richTextBox1.Size = new System.Drawing.Size(500, 220); + this.richTextBox1.Size = new System.Drawing.Size(502, 156); this.richTextBox1.TabIndex = 0; this.richTextBox1.Text = ""; // + // button1 + // + this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.button1.Enabled = false; + this.button1.Location = new System.Drawing.Point(422, 202); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(92, 23); + this.button1.TabIndex = 1; + this.button1.Text = "Send"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // // textBox1 // this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.textBox1.Location = new System.Drawing.Point(12, 238); + this.textBox1.Enabled = false; + this.textBox1.Location = new System.Drawing.Point(12, 202); this.textBox1.Name = "textBox1"; - this.textBox1.Size = new System.Drawing.Size(321, 22); - this.textBox1.TabIndex = 1; + this.textBox1.Size = new System.Drawing.Size(404, 22); + this.textBox1.TabIndex = 2; // - // button1 + // textBox2 // - this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.button1.Location = new System.Drawing.Point(339, 236); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(79, 23); - this.button1.TabIndex = 2; - this.button1.Text = "Send"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); + this.textBox2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBox2.Location = new System.Drawing.Point(12, 12); + this.textBox2.Name = "textBox2"; + this.textBox2.Size = new System.Drawing.Size(192, 22); + this.textBox2.TabIndex = 3; + this.textBox2.Text = "localhost"; + // + // textBox3 + // + this.textBox3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.textBox3.Location = new System.Drawing.Point(210, 12); + this.textBox3.Name = "textBox3"; + this.textBox3.RightToLeft = System.Windows.Forms.RightToLeft.Yes; + this.textBox3.Size = new System.Drawing.Size(108, 22); + this.textBox3.TabIndex = 4; + this.textBox3.Text = "14242"; // // button2 // - this.button2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.button2.Location = new System.Drawing.Point(424, 236); + this.button2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.button2.Location = new System.Drawing.Point(324, 12); this.button2.Name = "button2"; - this.button2.Size = new System.Drawing.Size(88, 23); - this.button2.TabIndex = 3; - this.button2.Text = "Settings"; + this.button2.Size = new System.Drawing.Size(92, 23); + this.button2.TabIndex = 5; + this.button2.Text = "Connect"; this.button2.UseVisualStyleBackColor = true; this.button2.Click += new System.EventHandler(this.button2_Click); // + // button3 + // + this.button3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.button3.Location = new System.Drawing.Point(422, 12); + this.button3.Name = "button3"; + this.button3.Size = new System.Drawing.Size(92, 23); + this.button3.TabIndex = 6; + this.button3.Text = "Settings"; + this.button3.UseVisualStyleBackColor = true; + this.button3.Click += new System.EventHandler(this.button3_Click); + // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(524, 272); + this.ClientSize = new System.Drawing.Size(526, 236); + this.Controls.Add(this.button3); this.Controls.Add(this.button2); - this.Controls.Add(this.button1); + this.Controls.Add(this.textBox3); + this.Controls.Add(this.textBox2); this.Controls.Add(this.textBox1); + this.Controls.Add(this.button1); this.Controls.Add(this.richTextBox1); this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Name = "Form1"; @@ -95,10 +134,13 @@ #endregion - public System.Windows.Forms.RichTextBox richTextBox1; - private System.Windows.Forms.TextBox textBox1; private System.Windows.Forms.Button button1; + private System.Windows.Forms.TextBox textBox1; private System.Windows.Forms.Button button2; + public System.Windows.Forms.RichTextBox richTextBox1; + public System.Windows.Forms.TextBox textBox2; + public System.Windows.Forms.TextBox textBox3; + private System.Windows.Forms.Button button3; } } diff --git a/Samples/Chat/ChatClient/Form1.cs b/Samples/Chat/ChatClient/Form1.cs new file mode 100644 index 0000000..c39d141 --- /dev/null +++ b/Samples/Chat/ChatClient/Form1.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Text; +using System.Windows.Forms; + +namespace ChatClient +{ + public partial class Form1 : Form + { + public Form1() + { + InitializeComponent(); + + textBox1.KeyDown += new KeyEventHandler(textBox1_KeyDown); + } + + public void EnableInput() + { + textBox1.Enabled = true; + button1.Enabled = true; + } + + public void DisableInput() + { + textBox1.Enabled = false; + button1.Enabled = false; + } + + void textBox1_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Return || e.KeyCode == Keys.Enter) + { + // return is equivalent to clicking "send" + button1_Click(sender, e); + } + } + + private void button3_Click(object sender, EventArgs e) + { + Program.DisplaySettings(); + } + + private void button2_Click(object sender, EventArgs e) + { + if (button2.Text == "Connect") + { + int port; + Int32.TryParse(textBox3.Text, out port); + Program.Connect(textBox2.Text, port); + button2.Text = "Shut down"; + } + else + { + Program.Shutdown(); + button2.Text = "Connect"; + } + } + + private void button1_Click(object sender, EventArgs e) + { + // Send + if (!string.IsNullOrEmpty(textBox1.Text)) + Program.Send(textBox1.Text); + textBox1.Text = ""; + + } + } +} diff --git a/Samples/ChatClient/Form1.resx b/Samples/Chat/ChatClient/Form1.resx similarity index 100% rename from Samples/ChatClient/Form1.resx rename to Samples/Chat/ChatClient/Form1.resx diff --git a/Samples/Chat/ChatClient/Program.cs b/Samples/Chat/ChatClient/Program.cs new file mode 100644 index 0000000..65c236c --- /dev/null +++ b/Samples/Chat/ChatClient/Program.cs @@ -0,0 +1,115 @@ +using System; +using System.Threading; +using System.Windows.Forms; + +using Lidgren.Network; + +using SamplesCommon; + +namespace ChatClient +{ + static class Program + { + private static NetClient s_client; + private static Form1 s_form; + private static NetPeerSettingsWindow s_settingsWindow; + + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + s_form = new Form1(); + + NetPeerConfiguration config = new NetPeerConfiguration("chat"); + s_client = new NetClient(config); + + Application.Idle += new EventHandler(Application_Idle); + + Application.Run(s_form); + } + + private static void Output(string text) + { + NativeMethods.AppendText(s_form.richTextBox1, text); + } + + private static void Application_Idle(object sender, EventArgs e) + { + while (NativeMethods.AppStillIdle) + { + NetIncomingMessage im; + while ((im = s_client.ReadMessage()) != null) + { + // handle incoming message + switch (im.MessageType) + { + case NetIncomingMessageType.DebugMessage: + case NetIncomingMessageType.ErrorMessage: + case NetIncomingMessageType.WarningMessage: + case NetIncomingMessageType.VerboseDebugMessage: + string text = im.ReadString(); + Output(text); + break; + case NetIncomingMessageType.StatusChanged: + NetConnectionStatus status = (NetConnectionStatus)im.ReadByte(); + + if (status == NetConnectionStatus.Connected) + s_form.EnableInput(); + else + s_form.DisableInput(); + string reason = im.ReadString(); + Output(status.ToString() + ": " + reason); + + break; + case NetIncomingMessageType.Data: + string chat = im.ReadString(); + Output(chat); + break; + default: + Output("Unhandled type: " + im.MessageType); + break; + } + } + Thread.Sleep(1); + } + } + + // called by the UI + public static void Connect(string host, int port) + { + s_client.Start(); + NetOutgoingMessage hail = s_client.CreateMessage(); + hail.Write("This is the hail message"); + s_client.Connect(host, port, hail); + } + + // called by the UI + public static void Shutdown() + { + s_client.Shutdown("Requested by user"); + } + + public static void Send(string text) + { + NetOutgoingMessage om = s_client.CreateMessage(text); + s_client.SendMessage(om, NetDeliveryMethod.ReliableOrdered); + Output("Sending '" + text + "'"); + } + + // called by the UI + public static void DisplaySettings() + { + if (s_settingsWindow != null && s_settingsWindow.Visible) + { + s_settingsWindow.Hide(); + } + else + { + if (s_settingsWindow == null || s_settingsWindow.IsDisposed) + s_settingsWindow = new NetPeerSettingsWindow("Chat client settings", s_client); + s_settingsWindow.Show(); + } + } + } +} diff --git a/Samples/ChatClient/Properties/AssemblyInfo.cs b/Samples/Chat/ChatClient/Properties/AssemblyInfo.cs similarity index 93% rename from Samples/ChatClient/Properties/AssemblyInfo.cs rename to Samples/Chat/ChatClient/Properties/AssemblyInfo.cs index 0524de3..5de4b0a 100644 --- a/Samples/ChatClient/Properties/AssemblyInfo.cs +++ b/Samples/Chat/ChatClient/Properties/AssemblyInfo.cs @@ -20,7 +20,7 @@ using System.Runtime.InteropServices; [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("2438660c-dd5f-45ac-bf17-69ed0b1c7dfa")] +[assembly: Guid("87051984-f522-47e0-b5ec-fca02571f83f")] // Version information for an assembly consists of the following four values: // diff --git a/Samples/ChatClient/Properties/Resources.Designer.cs b/Samples/Chat/ChatClient/Properties/Resources.Designer.cs similarity index 95% rename from Samples/ChatClient/Properties/Resources.Designer.cs rename to Samples/Chat/ChatClient/Properties/Resources.Designer.cs index e24e51d..87e4171 100644 --- a/Samples/ChatClient/Properties/Resources.Designer.cs +++ b/Samples/Chat/ChatClient/Properties/Resources.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.4927 +// Runtime Version:2.0.50727.4952 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Samples/ChatClient/Properties/Resources.resx b/Samples/Chat/ChatClient/Properties/Resources.resx similarity index 100% rename from Samples/ChatClient/Properties/Resources.resx rename to Samples/Chat/ChatClient/Properties/Resources.resx diff --git a/Samples/ChatClient/Properties/Settings.Designer.cs b/Samples/Chat/ChatClient/Properties/Settings.Designer.cs similarity index 93% rename from Samples/ChatClient/Properties/Settings.Designer.cs rename to Samples/Chat/ChatClient/Properties/Settings.Designer.cs index 59a1aa0..34d970f 100644 --- a/Samples/ChatClient/Properties/Settings.Designer.cs +++ b/Samples/Chat/ChatClient/Properties/Settings.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.4927 +// Runtime Version:2.0.50727.4952 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Samples/ChatClient/Properties/Settings.settings b/Samples/Chat/ChatClient/Properties/Settings.settings similarity index 100% rename from Samples/ChatClient/Properties/Settings.settings rename to Samples/Chat/ChatClient/Properties/Settings.settings diff --git a/Samples/ChatServer/ChatServer.csproj b/Samples/Chat/ChatServer/ChatServer.csproj similarity index 86% rename from Samples/ChatServer/ChatServer.csproj rename to Samples/Chat/ChatServer/ChatServer.csproj index bca2ec8..da2d7c0 100644 --- a/Samples/ChatServer/ChatServer.csproj +++ b/Samples/Chat/ChatServer/ChatServer.csproj @@ -5,13 +5,17 @@ AnyCPU 9.0.21022 2.0 - {E2711561-B3C9-4580-B054-891CE54E15EE} + {C5473E52-7601-48CA-BFEB-1AB012F3D4BF} WinExe Properties ChatServer ChatServer v3.5 512 + SAK + SAK + SAK + SAK true @@ -35,11 +39,8 @@ 3.5 - - - @@ -74,11 +75,11 @@ - - {FA245447-5F23-4AA1-BD5F-8D2DDF33CFBD} + + {AE483C29-042E-4226-BA52-D247CE7676DA} Lidgren.Network - + {773069DA-B66E-4667-ADCB-0D215AD8CF3E} SamplesCommon diff --git a/Samples/Chat/ChatServer/Form1.Designer.cs b/Samples/Chat/ChatServer/Form1.Designer.cs new file mode 100644 index 0000000..b9d49eb --- /dev/null +++ b/Samples/Chat/ChatServer/Form1.Designer.cs @@ -0,0 +1,128 @@ +namespace ChatServer +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.listBox1 = new System.Windows.Forms.ListBox(); + this.button1 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.richTextBox1 = new System.Windows.Forms.RichTextBox(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.SuspendLayout(); + // + // listBox1 + // + this.listBox1.Dock = System.Windows.Forms.DockStyle.Fill; + this.listBox1.FormattingEnabled = true; + this.listBox1.Location = new System.Drawing.Point(0, 0); + this.listBox1.Name = "listBox1"; + this.listBox1.Size = new System.Drawing.Size(570, 147); + this.listBox1.TabIndex = 0; + // + // button1 + // + this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.button1.Location = new System.Drawing.Point(12, 327); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(75, 23); + this.button1.TabIndex = 1; + this.button1.Text = "Start"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // button2 + // + this.button2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.button2.Location = new System.Drawing.Point(507, 327); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(75, 23); + this.button2.TabIndex = 2; + this.button2.Text = "Settings"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); + // + // splitContainer1 + // + this.splitContainer1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.splitContainer1.Location = new System.Drawing.Point(12, 12); + this.splitContainer1.Name = "splitContainer1"; + this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.Controls.Add(this.listBox1); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.richTextBox1); + this.splitContainer1.Size = new System.Drawing.Size(570, 309); + this.splitContainer1.SplitterDistance = 154; + this.splitContainer1.TabIndex = 3; + // + // richTextBox1 + // + this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Fill; + this.richTextBox1.Location = new System.Drawing.Point(0, 0); + this.richTextBox1.Name = "richTextBox1"; + this.richTextBox1.Size = new System.Drawing.Size(570, 151); + this.richTextBox1.TabIndex = 0; + this.richTextBox1.Text = ""; + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(594, 358); + this.Controls.Add(this.splitContainer1); + this.Controls.Add(this.button2); + this.Controls.Add(this.button1); + this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Name = "Form1"; + this.Text = "Chat server"; + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel2.ResumeLayout(false); + this.splitContainer1.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.SplitContainer splitContainer1; + public System.Windows.Forms.RichTextBox richTextBox1; + public System.Windows.Forms.ListBox listBox1; + } +} + diff --git a/Samples/Chat/ChatServer/Form1.cs b/Samples/Chat/ChatServer/Form1.cs new file mode 100644 index 0000000..8c5b2d5 --- /dev/null +++ b/Samples/Chat/ChatServer/Form1.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; +using System.Windows.Forms; + +namespace ChatServer +{ + public partial class Form1 : Form + { + public Form1() + { + InitializeComponent(); + } + + private void button1_Click(object sender, EventArgs e) + { + if (button1.Text == "Start") + { + Program.StartServer(); + button1.Text = "Shut down"; + } + else + { + Program.Shutdown(); + button1.Text = "Start"; + } + } + + private void button2_Click(object sender, EventArgs e) + { + Program.DisplaySettings(); + } + } +} diff --git a/Samples/ChatServer/Form1.resx b/Samples/Chat/ChatServer/Form1.resx similarity index 100% rename from Samples/ChatServer/Form1.resx rename to Samples/Chat/ChatServer/Form1.resx diff --git a/Samples/Chat/ChatServer/Program.cs b/Samples/Chat/ChatServer/Program.cs new file mode 100644 index 0000000..2435972 --- /dev/null +++ b/Samples/Chat/ChatServer/Program.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Windows.Forms; + +using Lidgren.Network; + +using SamplesCommon; + +namespace ChatServer +{ + static class Program + { + private static Form1 s_form; + private static NetServer s_server; + private static NetPeerSettingsWindow s_settingsWindow; + + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + s_form = new Form1(); + + // set up network + NetPeerConfiguration config = new NetPeerConfiguration("chat"); + config.MaximumConnections = 100; + config.Port = 14242; + s_server = new NetServer(config); + + Application.Idle += new EventHandler(Application_Idle); + Application.Run(s_form); + } + + private static void Output(string text) + { + NativeMethods.AppendText(s_form.richTextBox1, text); + } + + private static void Application_Idle(object sender, EventArgs e) + { + while (NativeMethods.AppStillIdle) + { + NetIncomingMessage im; + while ((im = s_server.ReadMessage()) != null) + { + // handle incoming message + switch (im.MessageType) + { + case NetIncomingMessageType.DebugMessage: + case NetIncomingMessageType.ErrorMessage: + case NetIncomingMessageType.WarningMessage: + case NetIncomingMessageType.VerboseDebugMessage: + string text = im.ReadString(); + Output(text); + break; + case NetIncomingMessageType.StatusChanged: + NetConnectionStatus status = (NetConnectionStatus)im.ReadByte(); + string reason = im.ReadString(); + Output(NetUtility.ToHexString(im.SenderConnection.RemoteUniqueIdentifier) + " " + status + ": " + reason); + + UpdateConnectionsList(); + break; + case NetIncomingMessageType.Data: + // incoming chat message from a client + string chat = im.ReadString(); + + Output("Broadcasting '" + chat + "'"); + + // broadcast this to all connections, except sender + List all = s_server.Connections; // get copy + all.Remove(im.SenderConnection); + + NetOutgoingMessage om = s_server.CreateMessage(); + om.Write(NetUtility.ToHexString(im.SenderConnection.RemoteUniqueIdentifier) + " said: " + chat); + + s_server.SendMessage(om, all, NetDeliveryMethod.ReliableOrdered, 0); + break; + default: + Output("Unhandled type: " + im.MessageType); + break; + } + } + Thread.Sleep(1); + } + } + + private static void UpdateConnectionsList() + { + s_form.listBox1.Items.Clear(); + + foreach (NetConnection conn in s_server.Connections) + { + string str = NetUtility.ToHexString(conn.RemoteUniqueIdentifier) + " from " + conn.RemoteEndpoint.ToString() + " [" + conn.Status + "]"; + s_form.listBox1.Items.Add(str); + } + } + + // called by the UI + public static void StartServer() + { + s_server.Start(); + } + + // called by the UI + public static void Shutdown() + { + s_server.Shutdown("Requested by user"); + } + + // called by the UI + public static void DisplaySettings() + { + if (s_settingsWindow != null && s_settingsWindow.Visible) + { + s_settingsWindow.Hide(); + } + else + { + if (s_settingsWindow == null || s_settingsWindow.IsDisposed) + s_settingsWindow = new NetPeerSettingsWindow("Chat server settings", s_server); + s_settingsWindow.Show(); + } + } + } +} diff --git a/Samples/ChatServer/Properties/AssemblyInfo.cs b/Samples/Chat/ChatServer/Properties/AssemblyInfo.cs similarity index 93% rename from Samples/ChatServer/Properties/AssemblyInfo.cs rename to Samples/Chat/ChatServer/Properties/AssemblyInfo.cs index 4fe7863..d264dfb 100644 --- a/Samples/ChatServer/Properties/AssemblyInfo.cs +++ b/Samples/Chat/ChatServer/Properties/AssemblyInfo.cs @@ -20,7 +20,7 @@ using System.Runtime.InteropServices; [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("2438660c-dd5f-45ac-bf17-69ed0b1c7dfa")] +[assembly: Guid("24166e15-7d4e-43eb-9e7d-da6215da8e0f")] // Version information for an assembly consists of the following four values: // diff --git a/Samples/ChatServer/Properties/Resources.Designer.cs b/Samples/Chat/ChatServer/Properties/Resources.Designer.cs similarity index 95% rename from Samples/ChatServer/Properties/Resources.Designer.cs rename to Samples/Chat/ChatServer/Properties/Resources.Designer.cs index 6b80a71..cc60cbd 100644 --- a/Samples/ChatServer/Properties/Resources.Designer.cs +++ b/Samples/Chat/ChatServer/Properties/Resources.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.4927 +// Runtime Version:2.0.50727.4952 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Samples/ChatServer/Properties/Resources.resx b/Samples/Chat/ChatServer/Properties/Resources.resx similarity index 100% rename from Samples/ChatServer/Properties/Resources.resx rename to Samples/Chat/ChatServer/Properties/Resources.resx diff --git a/Samples/ChatServer/Properties/Settings.Designer.cs b/Samples/Chat/ChatServer/Properties/Settings.Designer.cs similarity index 93% rename from Samples/ChatServer/Properties/Settings.Designer.cs rename to Samples/Chat/ChatServer/Properties/Settings.Designer.cs index b8aa7ce..517acf3 100644 --- a/Samples/ChatServer/Properties/Settings.Designer.cs +++ b/Samples/Chat/ChatServer/Properties/Settings.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.4927 +// Runtime Version:2.0.50727.4952 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Samples/ChatServer/Properties/Settings.settings b/Samples/Chat/ChatServer/Properties/Settings.settings similarity index 100% rename from Samples/ChatServer/Properties/Settings.settings rename to Samples/Chat/ChatServer/Properties/Settings.settings diff --git a/Samples/ChatClient/Form1.cs b/Samples/ChatClient/Form1.cs deleted file mode 100644 index 6aaf270..0000000 --- a/Samples/ChatClient/Form1.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Windows.Forms; -using SamplesCommon; - -namespace ChatClient -{ - public partial class Form1 : Form - { - public Form1() - { - InitializeComponent(); - - textBox1.KeyDown += new KeyEventHandler(textBox1_KeyDown); - } - - void textBox1_KeyDown(object sender, KeyEventArgs e) - { - if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Return) - { - string txt = textBox1.Text.Trim(); - Program.Input(txt); - textBox1.Text = ""; - } - } - - private void button2_Click(object sender, EventArgs e) - { - if (Program.SettingsWindow == null || Program.SettingsWindow.IsDisposed) - Program.SettingsWindow = new NetPeerSettingsWindow("Client settings", Program.Client); - if (Program.SettingsWindow.Visible) - Program.SettingsWindow.Hide(); - else - Program.SettingsWindow.Show(); - } - - private void button1_Click(object sender, EventArgs e) - { - string txt = textBox1.Text.Trim(); - Program.Input(txt); - textBox1.Text = ""; - } - } -} diff --git a/Samples/ChatClient/Program.cs b/Samples/ChatClient/Program.cs deleted file mode 100644 index f87686f..0000000 --- a/Samples/ChatClient/Program.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; -using System.Threading; -using System.Windows.Forms; - -using Lidgren.Network; - -using SamplesCommon; - -namespace ChatClient -{ - public class ChatMessage - { - public string Sender; - public string Text; - } - - static class Program - { - public static Form1 MainForm; - public static NetClient Client; - public static NetPeerSettingsWindow SettingsWindow; - - [STAThread] - static void Main() - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - MainForm = new Form1(); - - NetPeerConfiguration config = new NetPeerConfiguration("Chat"); - Client = new NetClient(config); - Client.Start(); - - Display("Type 'connect ' to connect to a server"); - - Application.Idle += new EventHandler(AppLoop); - Application.Run(MainForm); - } - - private static void Display(string text) - { - NativeMethods.AppendText(MainForm.richTextBox1, text); - } - - public static void Input(string input) - { - if (string.IsNullOrEmpty(input)) - return; - - if (input.ToLowerInvariant().StartsWith("connect ")) - { - string host = input.Substring(8).Trim(); - if (string.IsNullOrEmpty(host)) - host = "localhost"; - - Client.Connect(host, 14242); - return; - } - - // send chat message - ChatMessage cm = new ChatMessage(); - cm.Sender = Client.UniqueIdentifier.ToString(); - cm.Text = input; - - NetOutgoingMessage om = Client.CreateMessage(); - om.WriteAllFields(cm); - Client.SendMessage(om, NetDeliveryMethod.ReliableOrdered, 1); - } - - static void AppLoop(object sender, EventArgs e) - { - while (NativeMethods.AppStillIdle) - { - NetIncomingMessage msg = Client.ReadMessage(); - if (msg != null) - { - switch (msg.MessageType) - { - case NetIncomingMessageType.VerboseDebugMessage: - case NetIncomingMessageType.DebugMessage: - case NetIncomingMessageType.ErrorMessage: - case NetIncomingMessageType.WarningMessage: - // print any diagnostics message - Display(msg.ReadString()); - break; - - case NetIncomingMessageType.StatusChanged: - // print changes in connection(s) status - NetConnectionStatus status = (NetConnectionStatus)msg.ReadByte(); - string reason = msg.ReadString(); - Display("Status: " + status + " (" + reason + ")"); - - break; - - case NetIncomingMessageType.Data: - - ChatMessage cm = new ChatMessage(); - msg.ReadAllFields(cm); - - Display("Received from " + cm.Sender + ": " + cm.Text); - break; - } - Client.Recycle(msg); - } - Thread.Sleep(1); - } - } - } -} diff --git a/Samples/ChatServer/Form1.Designer.cs b/Samples/ChatServer/Form1.Designer.cs deleted file mode 100644 index 58d0b82..0000000 --- a/Samples/ChatServer/Form1.Designer.cs +++ /dev/null @@ -1,77 +0,0 @@ -namespace ChatServer -{ - partial class Form1 - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.richTextBox1 = new System.Windows.Forms.RichTextBox(); - this.button1 = new System.Windows.Forms.Button(); - this.SuspendLayout(); - // - // richTextBox1 - // - this.richTextBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.richTextBox1.Location = new System.Drawing.Point(12, 12); - this.richTextBox1.Name = "richTextBox1"; - this.richTextBox1.Size = new System.Drawing.Size(500, 221); - this.richTextBox1.TabIndex = 0; - this.richTextBox1.Text = ""; - // - // button1 - // - this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.button1.Location = new System.Drawing.Point(12, 239); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(103, 23); - this.button1.TabIndex = 1; - this.button1.Text = "Settings"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); - // - // Form1 - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(524, 272); - this.Controls.Add(this.button1); - this.Controls.Add(this.richTextBox1); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.Name = "Form1"; - this.Text = "Chat server"; - this.ResumeLayout(false); - - } - - #endregion - - public System.Windows.Forms.RichTextBox richTextBox1; - private System.Windows.Forms.Button button1; - } -} - diff --git a/Samples/ChatServer/Form1.cs b/Samples/ChatServer/Form1.cs deleted file mode 100644 index b27f291..0000000 --- a/Samples/ChatServer/Form1.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Windows.Forms; -using SamplesCommon; - -namespace ChatServer -{ - public partial class Form1 : Form - { - public Form1() - { - InitializeComponent(); - } - - private void button1_Click(object sender, EventArgs e) - { - if (Program.SettingsWindow == null || Program.SettingsWindow.IsDisposed) - Program.SettingsWindow = new NetPeerSettingsWindow("Client settings", Program.Server); - if (Program.SettingsWindow.Visible) - Program.SettingsWindow.Hide(); - else - Program.SettingsWindow.Show(); - } - } -} diff --git a/Samples/ChatServer/Program.cs b/Samples/ChatServer/Program.cs deleted file mode 100644 index 320d195..0000000 --- a/Samples/ChatServer/Program.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using System.Threading; -using System.Windows.Forms; - -using Lidgren.Network; - -using SamplesCommon; - -namespace ChatServer -{ - public class ChatMessage - { - public string Sender { get; set; } - public string Text { get; set; } - } - - static class Program - { - public static Form1 MainForm; - public static NetServer Server; - public static NetPeerSettingsWindow SettingsWindow; - - [STAThread] - static void Main() - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - MainForm = new Form1(); - - // create a configuration - NetPeerConfiguration config = new NetPeerConfiguration("Chat"); - config.Port = 14242; - - // create and start server - Server = new NetServer(config); - Server.Start(); - - Application.Idle += new EventHandler(AppLoop); - Application.Run(MainForm); - } - - private static void Display(string text) - { - NativeMethods.AppendText(MainForm.richTextBox1, text); - } - - static void AppLoop(object sender, EventArgs e) - { - while (NativeMethods.AppStillIdle) - { - NetIncomingMessage msg = Server.WaitMessage(100); - if (msg != null) - { - switch (msg.MessageType) - { - case NetIncomingMessageType.VerboseDebugMessage: - case NetIncomingMessageType.DebugMessage: - case NetIncomingMessageType.ErrorMessage: - case NetIncomingMessageType.WarningMessage: - // print any library message - Display(msg.ReadString()); - break; - - case NetIncomingMessageType.StatusChanged: - // print changes in connection(s) status - NetConnectionStatus status = (NetConnectionStatus)msg.ReadByte(); - string reason = msg.ReadString(); - Display(msg.SenderConnection + " status: " + status + " (" + reason + ")"); - - break; - - case NetIncomingMessageType.Data: - - // read chat message - ChatMessage cm = new ChatMessage(); - msg.ReadAllProperties(cm); - - // Forward all data to all clients (including sender for debugging purposes) - NetOutgoingMessage om = Server.CreateMessage(); - om.WriteAllProperties(cm, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); - - Display("Forwarding text from " + cm.Sender + " (seqchan " + msg.SequenceChannel + ") to all clients: " + cm.Text); - Server.SendMessage(om, Server.Connections, NetDeliveryMethod.ReliableOrdered, 0); - - break; - } - Server.Recycle(msg); - } - } - } - } -} diff --git a/Samples/DurableClient/DurableClient.csproj b/Samples/DurableClient/DurableClient.csproj deleted file mode 100644 index f89b8b2..0000000 --- a/Samples/DurableClient/DurableClient.csproj +++ /dev/null @@ -1,94 +0,0 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {0B4B02BB-0F43-4466-A369-0682281AF60E} - WinExe - Properties - DurableClient - DurableClient - v3.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - 3.5 - - - - - - - - - - Form - - - Form1.cs - - - - - Form1.cs - Designer - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - {FA245447-5F23-4AA1-BD5F-8D2DDF33CFBD} - Lidgren.Network - - - {773069DA-B66E-4667-ADCB-0D215AD8CF3E} - SamplesCommon - - - - - \ No newline at end of file diff --git a/Samples/DurableClient/Form1.Designer.cs b/Samples/DurableClient/Form1.Designer.cs deleted file mode 100644 index 017687c..0000000 --- a/Samples/DurableClient/Form1.Designer.cs +++ /dev/null @@ -1,112 +0,0 @@ -namespace DurableClient -{ - partial class Form1 - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.richTextBox1 = new System.Windows.Forms.RichTextBox(); - this.button1 = new System.Windows.Forms.Button(); - this.textBox1 = new System.Windows.Forms.TextBox(); - this.label1 = new System.Windows.Forms.Label(); - this.button2 = new System.Windows.Forms.Button(); - this.SuspendLayout(); - // - // richTextBox1 - // - this.richTextBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.richTextBox1.Location = new System.Drawing.Point(12, 218); - this.richTextBox1.Name = "richTextBox1"; - this.richTextBox1.Size = new System.Drawing.Size(493, 124); - this.richTextBox1.TabIndex = 0; - this.richTextBox1.Text = ""; - // - // button1 - // - this.button1.Location = new System.Drawing.Point(232, 10); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(75, 23); - this.button1.TabIndex = 1; - this.button1.Text = "Connect"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); - // - // textBox1 - // - this.textBox1.Location = new System.Drawing.Point(12, 12); - this.textBox1.Name = "textBox1"; - this.textBox1.Size = new System.Drawing.Size(214, 22); - this.textBox1.TabIndex = 2; - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(12, 40); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(38, 13); - this.label1.TabIndex = 3; - this.label1.Text = "label1"; - // - // button2 - // - this.button2.Location = new System.Drawing.Point(313, 10); - this.button2.Name = "button2"; - this.button2.Size = new System.Drawing.Size(75, 23); - this.button2.TabIndex = 4; - this.button2.Text = "Settings"; - this.button2.UseVisualStyleBackColor = true; - this.button2.Click += new System.EventHandler(this.button2_Click); - // - // Form1 - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(517, 354); - this.Controls.Add(this.button2); - this.Controls.Add(this.label1); - this.Controls.Add(this.textBox1); - this.Controls.Add(this.button1); - this.Controls.Add(this.richTextBox1); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.Name = "Form1"; - this.Text = "Form1"; - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - public System.Windows.Forms.RichTextBox richTextBox1; - private System.Windows.Forms.Button button1; - private System.Windows.Forms.TextBox textBox1; - public System.Windows.Forms.Label label1; - private System.Windows.Forms.Button button2; - } -} - diff --git a/Samples/DurableClient/Form1.cs b/Samples/DurableClient/Form1.cs deleted file mode 100644 index 4546ac8..0000000 --- a/Samples/DurableClient/Form1.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Windows.Forms; -using SamplesCommon; - -namespace DurableClient -{ - public partial class Form1 : Form - { - private NetPeerSettingsWindow m_settingsWindow; - - public Form1() - { - InitializeComponent(); - } - - private void button1_Click(object sender, EventArgs e) - { - if (string.IsNullOrEmpty(textBox1.Text)) - textBox1.Text = "localhost"; - - Program.Connect(textBox1.Text); - } - - private void button2_Click(object sender, EventArgs e) - { - if (m_settingsWindow == null) - { - m_settingsWindow = new NetPeerSettingsWindow("Durable client settings", Program.Client); - m_settingsWindow.Show(); - } - else - { - m_settingsWindow.Close(); - m_settingsWindow = null; - } - } - } -} diff --git a/Samples/DurableClient/Form1.resx b/Samples/DurableClient/Form1.resx deleted file mode 100644 index ff31a6d..0000000 --- a/Samples/DurableClient/Form1.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Samples/DurableClient/Program.cs b/Samples/DurableClient/Program.cs deleted file mode 100644 index 493209d..0000000 --- a/Samples/DurableClient/Program.cs +++ /dev/null @@ -1,149 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Windows.Forms; - -using System.Threading; -using Lidgren.Network; -using SamplesCommon; -using System.Text; - -namespace DurableClient -{ - static class Program - { - public static Form1 MainForm; - public static NetClient Client; - - private static bool s_sendStuff; - - [STAThread] - static void Main() - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - MainForm = new Form1(); - - NetPeerConfiguration config = new NetPeerConfiguration("durable"); - Client = new NetClient(config); - Client.Start(); - - Application.Idle += new EventHandler(AppLoop); - Application.Run(MainForm); - - Client.Shutdown("App exiting"); - } - - public static void Display(string text) - { - NativeMethods.AppendText(MainForm.richTextBox1, text); - } - - private static double s_nextSendReliableOrdered; - private static uint[] s_reliableOrderedNr = new uint[3]; - - private static double s_nextSendSequenced; - private static uint[] s_sequencedNr = new uint[3]; - - private static double s_lastLabelUpdate; - private const double kLabelUpdateFrequency = 0.25; - - static void AppLoop(object sender, EventArgs e) - { - while (NativeMethods.AppStillIdle) - { - NetIncomingMessage msg; - while ((msg = Client.WaitMessage(1)) != null) - { - switch (msg.MessageType) - { - case NetIncomingMessageType.VerboseDebugMessage: - case NetIncomingMessageType.DebugMessage: - case NetIncomingMessageType.WarningMessage: - case NetIncomingMessageType.ErrorMessage: - Display(msg.ReadString()); - break; - case NetIncomingMessageType.Data: - Display("Received data?!"); - break; - case NetIncomingMessageType.StatusChanged: - NetConnectionStatus status = (NetConnectionStatus)msg.ReadByte(); - string reason = msg.ReadString(); - Display("New status: " + status + " (" + reason + ")"); - - if (status == NetConnectionStatus.Connected) - { - // go - s_sendStuff = true; - } - break; - } - Client.Recycle(msg); - } - - if (s_sendStuff) - { - double now = NetTime.Now; - - float speed = 1.0f; - - float speedMultiplier = 1.0f / speed; - - int r = NetRandom.Instance.Next(3); - if (now > s_nextSendReliableOrdered) - { - NetOutgoingMessage om = Client.CreateMessage(5); - - uint rv = s_reliableOrderedNr[r]; - s_reliableOrderedNr[r]++; - - om.Write(rv); - - Client.SendMessage(om, NetDeliveryMethod.ReliableOrdered, r); - s_nextSendReliableOrdered = now + (NetRandom.Instance.NextFloat() * (0.01f * speedMultiplier)) + (0.005f * speedMultiplier); - } - - if (now > s_nextSendSequenced) - { - NetOutgoingMessage om = Client.CreateMessage(); - - uint v = s_sequencedNr[r]; - s_sequencedNr[r]++; - om.Write(v); - Client.SendMessage(om, NetDeliveryMethod.UnreliableSequenced, r); - s_nextSendSequenced = now + (NetRandom.Instance.NextFloat() * (0.01f * speedMultiplier)) + (0.005f * speedMultiplier); - } - - if (now > s_lastLabelUpdate + kLabelUpdateFrequency) - { - UpdateLabel(); - s_lastLabelUpdate = now; - } - } - } - } - - private static void UpdateLabel() - { - NetConnection conn = Client.ServerConnection; - if (conn != null) - { - StringBuilder bdr = new StringBuilder(); - bdr.Append(Client.Statistics.ToString()); - bdr.Append(conn.Statistics.ToString()); - - bdr.AppendLine("SENT Reliable ordered: " + s_reliableOrderedNr[0] + ", " + s_reliableOrderedNr[1] + ", " + s_reliableOrderedNr[2]); - bdr.AppendLine("SENT Sequenced: " + s_sequencedNr[0] + ", " + s_sequencedNr[1] + ", " + s_sequencedNr[2]); - bdr.AppendLine("Unsent bytes: " + conn.UnsentBytesCount); - MainForm.label1.Text = bdr.ToString(); - } - } - - public static void Connect(string host) - { - NetOutgoingMessage approval = Client.CreateMessage(); - approval.Write("durableschmurable"); - - Client.Connect(host, 14242, approval); - } - } -} diff --git a/Samples/DurableClient/Properties/AssemblyInfo.cs b/Samples/DurableClient/Properties/AssemblyInfo.cs deleted file mode 100644 index 335e685..0000000 --- a/Samples/DurableClient/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("DurableClient")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("DurableClient")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("2438660c-dd5f-45ac-bf17-69ed0b1c7dfa")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Samples/DurableClient/Properties/Resources.Designer.cs b/Samples/DurableClient/Properties/Resources.Designer.cs deleted file mode 100644 index 37f440d..0000000 --- a/Samples/DurableClient/Properties/Resources.Designer.cs +++ /dev/null @@ -1,71 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:2.0.50727.4927 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace DurableClient.Properties -{ - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources - { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if ((resourceMan == null)) - { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DurableClient.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { - return resourceCulture; - } - set - { - resourceCulture = value; - } - } - } -} diff --git a/Samples/DurableClient/Properties/Resources.resx b/Samples/DurableClient/Properties/Resources.resx deleted file mode 100644 index ffecec8..0000000 --- a/Samples/DurableClient/Properties/Resources.resx +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Samples/DurableClient/Properties/Settings.Designer.cs b/Samples/DurableClient/Properties/Settings.Designer.cs deleted file mode 100644 index 77adcdd..0000000 --- a/Samples/DurableClient/Properties/Settings.Designer.cs +++ /dev/null @@ -1,30 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:2.0.50727.4927 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace DurableClient.Properties -{ - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase - { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default - { - get - { - return defaultInstance; - } - } - } -} diff --git a/Samples/DurableClient/Properties/Settings.settings b/Samples/DurableClient/Properties/Settings.settings deleted file mode 100644 index abf36c5..0000000 --- a/Samples/DurableClient/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Samples/DurableServer/DurableServer.csproj b/Samples/DurableServer/DurableServer.csproj deleted file mode 100644 index 8ce4de9..0000000 --- a/Samples/DurableServer/DurableServer.csproj +++ /dev/null @@ -1,94 +0,0 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {034984CA-FB37-44AF-BBF9-EC58ED75F5F3} - WinExe - Properties - DurableServer - DurableServer - v3.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - 3.5 - - - - - - - - - - Form - - - Form1.cs - - - - - Form1.cs - Designer - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - {FA245447-5F23-4AA1-BD5F-8D2DDF33CFBD} - Lidgren.Network - - - {773069DA-B66E-4667-ADCB-0D215AD8CF3E} - SamplesCommon - - - - - \ No newline at end of file diff --git a/Samples/DurableServer/Form1.Designer.cs b/Samples/DurableServer/Form1.Designer.cs deleted file mode 100644 index 0df7cc4..0000000 --- a/Samples/DurableServer/Form1.Designer.cs +++ /dev/null @@ -1,89 +0,0 @@ -namespace DurableServer -{ - partial class Form1 - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.richTextBox1 = new System.Windows.Forms.RichTextBox(); - this.label1 = new System.Windows.Forms.Label(); - this.button1 = new System.Windows.Forms.Button(); - this.SuspendLayout(); - // - // richTextBox1 - // - this.richTextBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.richTextBox1.Location = new System.Drawing.Point(12, 229); - this.richTextBox1.Name = "richTextBox1"; - this.richTextBox1.Size = new System.Drawing.Size(543, 167); - this.richTextBox1.TabIndex = 0; - this.richTextBox1.Text = ""; - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(12, 9); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(38, 13); - this.label1.TabIndex = 1; - this.label1.Text = "label1"; - // - // button1 - // - this.button1.Location = new System.Drawing.Point(480, 200); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(75, 23); - this.button1.TabIndex = 2; - this.button1.Text = "Settings"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); - // - // Form1 - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(567, 408); - this.Controls.Add(this.button1); - this.Controls.Add(this.label1); - this.Controls.Add(this.richTextBox1); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.Name = "Form1"; - this.Text = "Durable server"; - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - public System.Windows.Forms.RichTextBox richTextBox1; - public System.Windows.Forms.Label label1; - private System.Windows.Forms.Button button1; - } -} - diff --git a/Samples/DurableServer/Form1.cs b/Samples/DurableServer/Form1.cs deleted file mode 100644 index 0a7f193..0000000 --- a/Samples/DurableServer/Form1.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Windows.Forms; -using SamplesCommon; - -namespace DurableServer -{ - public partial class Form1 : Form - { - private NetPeerSettingsWindow m_settingsWindow; - - public Form1() - { - InitializeComponent(); - } - - private void button1_Click(object sender, EventArgs e) - { - if (m_settingsWindow == null) - { - m_settingsWindow = new NetPeerSettingsWindow("Durable server settings", Program.Server); - m_settingsWindow.Show(); - } - else - { - m_settingsWindow.Close(); - m_settingsWindow = null; - } - } - } -} diff --git a/Samples/DurableServer/Form1.resx b/Samples/DurableServer/Form1.resx deleted file mode 100644 index ff31a6d..0000000 --- a/Samples/DurableServer/Form1.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Samples/DurableServer/Program.cs b/Samples/DurableServer/Program.cs deleted file mode 100644 index a857c35..0000000 --- a/Samples/DurableServer/Program.cs +++ /dev/null @@ -1,166 +0,0 @@ -using System; -using System.Threading; -using System.Windows.Forms; - -using Lidgren.Network; - -using SamplesCommon; -using System.Text; - -namespace DurableServer -{ - static class Program - { - public static Form1 MainForm; - public static NetServer Server; - - [STAThread] - static void Main() - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - MainForm = new Form1(); - - NetPeerConfiguration config = new NetPeerConfiguration("durable"); - config.Port = 14242; - config.EnableMessageType(NetIncomingMessageType.ConnectionApproval); - Server = new NetServer(config); - Server.Start(); - - m_expectedReliableOrdered = new uint[3]; - m_reliableOrderedCorrect = new int[3]; - m_reliableOrderedErrors = new int[3]; - - m_expectedSequenced = new uint[3]; - m_sequencedCorrect = new int[3]; - m_sequencedErrors = new int[3]; - - Application.Idle += new EventHandler(AppLoop); - Application.Run(MainForm); - - Server.Shutdown("App exiting"); - } - - private static void Display(string text) - { - NativeMethods.AppendText(MainForm.richTextBox1, text); - } - - private static double m_lastLabelUpdate; - private const double kLabelUpdateFrequency = 0.25; - - private static uint[] m_expectedReliableOrdered; - private static int[] m_reliableOrderedCorrect; - private static int[] m_reliableOrderedErrors; - - private static uint[] m_expectedSequenced; - private static int[] m_sequencedCorrect; - private static int[] m_sequencedErrors; - - static void AppLoop(object sender, EventArgs e) - { - while (NativeMethods.AppStillIdle) - { - NetIncomingMessage msg; - while ((msg = Server.ReadMessage()) != null) - { - switch (msg.MessageType) - { - case NetIncomingMessageType.VerboseDebugMessage: - case NetIncomingMessageType.DebugMessage: - case NetIncomingMessageType.WarningMessage: - case NetIncomingMessageType.ErrorMessage: - Display(msg.ReadString()); - break; - case NetIncomingMessageType.ConnectionApproval: - string ok = msg.ReadString(); - if (ok == "durableschmurable") - msg.SenderConnection.Approve(); - else - msg.SenderConnection.Deny("You didn't say the secret word!"); - break; - case NetIncomingMessageType.StatusChanged: - NetConnectionStatus status = (NetConnectionStatus)msg.ReadByte(); - string reason = msg.ReadString(); - Display("New status: " + status + " (" + reason + ")"); - break; - case NetIncomingMessageType.Data: - uint nr = msg.ReadUInt32(); - int chan = msg.SequenceChannel; - switch (msg.DeliveryMethod) - { - case NetDeliveryMethod.ReliableOrdered: - if (nr != m_expectedReliableOrdered[chan]) - { - //Display("Expected " + m_expectedReliableOrdered[chan] + ", got " + nr); - m_reliableOrderedErrors[chan]++; - m_expectedReliableOrdered[chan] = nr + 1; - } - else - { - m_reliableOrderedCorrect[chan]++; - m_expectedReliableOrdered[chan]++; - } - break; - case NetDeliveryMethod.UnreliableSequenced: - if (nr < m_expectedSequenced[chan]) - m_sequencedErrors[chan]++; - else - m_sequencedCorrect[chan]++; - m_expectedSequenced[chan] = nr + 1; - break; - default: - throw new Exception("Bad NetDeliveryMethod: " + msg.DeliveryMethod); - } - break; - } - Server.Recycle(msg); - } - Thread.Sleep(0); - - double now = NetTime.Now; - if (now > m_lastLabelUpdate + kLabelUpdateFrequency) - { - UpdateLabel(); - m_lastLabelUpdate = now; - } - } - } - - private static void UpdateLabel() - { - if (Server.ConnectionsCount < 1) - { - // don't update! Keep old... - const string oldData = "(Note: OLD DATA - NO CONNECTIONS NOW)"; - if (!MainForm.label1.Text.EndsWith(oldData)) - MainForm.label1.Text += oldData; - } - else - { - StringBuilder bdr = new StringBuilder(); - bdr.Append(Server.Statistics.ToString()); - bdr.Append(Server.Connections[0].Statistics.ToString()); - bdr.AppendLine("RECEIVED Reliable ordered: " + - m_reliableOrderedCorrect[0] + ", " + - m_reliableOrderedCorrect[1] + ", " + - m_reliableOrderedCorrect[2] + - " received; " + - m_reliableOrderedErrors[0] + ", " + - m_reliableOrderedErrors[1] + ", " + - m_reliableOrderedErrors[2] + - " errors"); - bdr.AppendLine("RECEIVED Sequenced: " + - m_sequencedCorrect[0] + ", " + - m_sequencedCorrect[1] + ", " + - m_sequencedCorrect[2] + - " received; " + - m_sequencedErrors[0] + ", " + - m_sequencedErrors[1] + ", " + - m_sequencedErrors[2] + - " errors"); - MainForm.label1.Text = bdr.ToString(); - } - } - } -} diff --git a/Samples/DurableServer/Properties/AssemblyInfo.cs b/Samples/DurableServer/Properties/AssemblyInfo.cs deleted file mode 100644 index e825b49..0000000 --- a/Samples/DurableServer/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("DurableServer")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("DurableServer")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("2438660c-dd5f-45ac-bf17-69ed0b1c7dfa")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Samples/DurableServer/Properties/Resources.Designer.cs b/Samples/DurableServer/Properties/Resources.Designer.cs deleted file mode 100644 index b898ce5..0000000 --- a/Samples/DurableServer/Properties/Resources.Designer.cs +++ /dev/null @@ -1,71 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:2.0.50727.4927 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace DurableServer.Properties -{ - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources - { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if ((resourceMan == null)) - { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DurableServer.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { - return resourceCulture; - } - set - { - resourceCulture = value; - } - } - } -} diff --git a/Samples/DurableServer/Properties/Resources.resx b/Samples/DurableServer/Properties/Resources.resx deleted file mode 100644 index ffecec8..0000000 --- a/Samples/DurableServer/Properties/Resources.resx +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Samples/DurableServer/Properties/Settings.Designer.cs b/Samples/DurableServer/Properties/Settings.Designer.cs deleted file mode 100644 index 41a0d0f..0000000 --- a/Samples/DurableServer/Properties/Settings.Designer.cs +++ /dev/null @@ -1,30 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:2.0.50727.4927 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace DurableServer.Properties -{ - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase - { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default - { - get - { - return defaultInstance; - } - } - } -} diff --git a/Samples/DurableServer/Properties/Settings.settings b/Samples/DurableServer/Properties/Settings.settings deleted file mode 100644 index abf36c5..0000000 --- a/Samples/DurableServer/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Samples/ImageClient/Form1.Designer.cs b/Samples/ImageClient/Form1.Designer.cs deleted file mode 100644 index 4525eb6..0000000 --- a/Samples/ImageClient/Form1.Designer.cs +++ /dev/null @@ -1,87 +0,0 @@ -namespace ImageClient -{ - partial class Form1 - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.textBox1 = new System.Windows.Forms.TextBox(); - this.button1 = new System.Windows.Forms.Button(); - this.button2 = new System.Windows.Forms.Button(); - this.SuspendLayout(); - // - // textBox1 - // - this.textBox1.Location = new System.Drawing.Point(12, 12); - this.textBox1.Name = "textBox1"; - this.textBox1.Size = new System.Drawing.Size(146, 22); - this.textBox1.TabIndex = 0; - this.textBox1.Text = "localhost"; - // - // button1 - // - this.button1.Location = new System.Drawing.Point(164, 12); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(161, 23); - this.button1.TabIndex = 1; - this.button1.Text = "Spawn imagegetter"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); - // - // button2 - // - this.button2.Location = new System.Drawing.Point(331, 12); - this.button2.Name = "button2"; - this.button2.Size = new System.Drawing.Size(129, 23); - this.button2.TabIndex = 2; - this.button2.Text = "Settings"; - this.button2.UseVisualStyleBackColor = true; - this.button2.Click += new System.EventHandler(this.button2_Click); - // - // Form1 - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(469, 44); - this.Controls.Add(this.button2); - this.Controls.Add(this.button1); - this.Controls.Add(this.textBox1); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.Name = "Form1"; - this.Text = "Image client"; - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.TextBox textBox1; - private System.Windows.Forms.Button button1; - private System.Windows.Forms.Button button2; - } -} - diff --git a/Samples/ImageClient/Form1.cs b/Samples/ImageClient/Form1.cs deleted file mode 100644 index d25420d..0000000 --- a/Samples/ImageClient/Form1.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Windows.Forms; -using Lidgren.Network; -using SamplesCommon; - -namespace ImageClient -{ - public partial class Form1 : Form - { - private NetPeer m_dummyPeer; - private NetPeerConfiguration m_config; - - public Form1() - { - m_config = new NetPeerConfiguration("ImageTransfer"); - m_dummyPeer = new NetPeer(m_config); - InitializeComponent(); - } - - private void button1_Click(object sender, EventArgs e) - { - Program.SpawnGetter(textBox1.Text, m_config); - } - - private void button2_Click(object sender, EventArgs e) - { - NetPeerSettingsWindow win = new NetPeerSettingsWindow("Client settings", m_dummyPeer); - win.Show(); - } - } -} diff --git a/Samples/ImageClient/Form1.resx b/Samples/ImageClient/Form1.resx deleted file mode 100644 index ff31a6d..0000000 --- a/Samples/ImageClient/Form1.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Samples/ImageClient/ImageClient.csproj b/Samples/ImageClient/ImageClient.csproj deleted file mode 100644 index 9070c75..0000000 --- a/Samples/ImageClient/ImageClient.csproj +++ /dev/null @@ -1,110 +0,0 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {69E64B8C-4736-4334-87BF-DD631A3AD144} - WinExe - Properties - ImageClient - ImageClient - v3.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - 3.5 - - - 3.5 - - - 3.5 - - - - - - - - - - Form - - - Form1.cs - - - Form - - - ImageGetter.cs - - - - - Form1.cs - Designer - - - ImageGetter.cs - Designer - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - {FA245447-5F23-4AA1-BD5F-8D2DDF33CFBD} - Lidgren.Network - - - {773069DA-B66E-4667-ADCB-0D215AD8CF3E} - SamplesCommon - - - - - \ No newline at end of file diff --git a/Samples/ImageClient/ImageGetter.Designer.cs b/Samples/ImageClient/ImageGetter.Designer.cs deleted file mode 100644 index cdf9e53..0000000 --- a/Samples/ImageClient/ImageGetter.Designer.cs +++ /dev/null @@ -1,72 +0,0 @@ -namespace ImageClient -{ - partial class ImageGetter - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.pictureBox1 = new System.Windows.Forms.PictureBox(); - this.richTextBox1 = new System.Windows.Forms.RichTextBox(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); - this.SuspendLayout(); - // - // pictureBox1 - // - this.pictureBox1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; - this.pictureBox1.Location = new System.Drawing.Point(12, 134); - this.pictureBox1.Name = "pictureBox1"; - this.pictureBox1.Size = new System.Drawing.Size(260, 238); - this.pictureBox1.TabIndex = 0; - this.pictureBox1.TabStop = false; - // - // richTextBox1 - // - this.richTextBox1.Location = new System.Drawing.Point(12, 12); - this.richTextBox1.Name = "richTextBox1"; - this.richTextBox1.Size = new System.Drawing.Size(562, 116); - this.richTextBox1.TabIndex = 1; - this.richTextBox1.Text = ""; - // - // ImageGetter - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(586, 521); - this.Controls.Add(this.richTextBox1); - this.Controls.Add(this.pictureBox1); - this.Name = "ImageGetter"; - this.Text = "ImageGetter"; - ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); - this.ResumeLayout(false); - - } - - #endregion - - private System.Windows.Forms.PictureBox pictureBox1; - public System.Windows.Forms.RichTextBox richTextBox1; - } -} \ No newline at end of file diff --git a/Samples/ImageClient/ImageGetter.cs b/Samples/ImageClient/ImageGetter.cs deleted file mode 100644 index 591457f..0000000 --- a/Samples/ImageClient/ImageGetter.cs +++ /dev/null @@ -1,158 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Text; -using System.Windows.Forms; -using Lidgren.Network; -using SamplesCommon; - -namespace ImageClient -{ - public partial class ImageGetter : Form - { - public NetClient Client; - public byte[] Buffer = new byte[990]; - public bool[] ReceivedSegments; - public int NumReceivedSegments; - - public ImageGetter(string host, NetPeerConfiguration copyConfig) - { - InitializeComponent(); - - NetPeerConfiguration config = copyConfig.Clone(); - config.EnableMessageType(NetIncomingMessageType.DiscoveryResponse); - - Client = new NetClient(config); - Client.Start(); - - Client.DiscoverLocalPeers(14242); - } - - public void Heartbeat() - { - NetIncomingMessage inc; - while ((inc = Client.ReadMessage()) != null) - { - switch(inc.MessageType) - { - case NetIncomingMessageType.DiscoveryResponse: - // found server! just connect... - - string serverResponseHello = inc.ReadString(); - - // create approval data - NetOutgoingMessage approval = Client.CreateMessage(); - approval.Write(42); - approval.Write("secret"); - - Client.Connect(inc.SenderEndpoint, approval); - break; - case NetIncomingMessageType.DebugMessage: - case NetIncomingMessageType.VerboseDebugMessage: - case NetIncomingMessageType.WarningMessage: - case NetIncomingMessageType.ErrorMessage: - string str = inc.ReadString(); - NativeMethods.AppendText(richTextBox1, str); - System.IO.File.AppendAllText("C:\\tmp\\clientlog.txt", str + Environment.NewLine); - break; - case NetIncomingMessageType.StatusChanged: - NetConnectionStatus status = (NetConnectionStatus)inc.ReadByte(); - string reason = inc.ReadString(); - NativeMethods.AppendText(richTextBox1, "New status: " + status + " (" + reason + ")"); - break; - case NetIncomingMessageType.Data: - // image data, whee! - // ineffective but simple data model - ushort width = inc.ReadUInt16(); - ushort height = inc.ReadUInt16(); - uint segment = inc.ReadVariableUInt32(); - - Bitmap bm = pictureBox1.Image as Bitmap; - if (bm == null) - { - bm = new Bitmap(width + 1, height + 1); - pictureBox1.Image = bm; - this.Size = new System.Drawing.Size(width + 40, height + 60); - pictureBox1.SetBounds(12, 12, width, height); - } - pictureBox1.SuspendLayout(); - - int totalBytes = (width * height * 3); - if (inc.LengthBytes < totalBytes) - { - int wholeSegments = totalBytes / 990; - int segLen = 990; - int remainder = totalBytes - (wholeSegments * inc.LengthBytes); - int totalNumberOfSegments = wholeSegments + (remainder > 0 ? 1 : 0); - if (segment >= wholeSegments) - segLen = remainder; // last segment can be shorter - - if (ReceivedSegments == null) - ReceivedSegments = new bool[totalNumberOfSegments]; - if (ReceivedSegments[segment] == false) - { - ReceivedSegments[segment] = true; - NumReceivedSegments++; - if (NumReceivedSegments >= totalNumberOfSegments) - { - Client.Disconnect("So long and thanks for all the fish!"); - } - } - - - - int pixelsAhead = (int)segment * 330; - - int y = pixelsAhead / width; - int x = pixelsAhead - (y * width); - - for (int i = 0; i < (segLen / 3); i++) - { - // set pixel - byte r = inc.ReadByte(); - byte g = inc.ReadByte(); - byte b = inc.ReadByte(); - Color col = Color.FromArgb(r, g, b); - bm.SetPixel(x, y, col); - x++; - if (x >= width) - { - x = 0; - y++; - } - } - } - else - { - - for(int y=0;y - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Samples/ImageClient/Program.cs b/Samples/ImageClient/Program.cs deleted file mode 100644 index a3a42a0..0000000 --- a/Samples/ImageClient/Program.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Windows.Forms; -using SamplesCommon; -using Lidgren.Network; - -namespace ImageClient -{ - static class Program - { - public static Form1 MainForm; - public static List Getters = new List(); - - [STAThread] - static void Main() - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - MainForm = new Form1(); - - Application.Idle += new EventHandler(AppLoop); - Application.Run(MainForm); - } - - static void AppLoop(object sender, EventArgs e) - { - foreach (ImageGetter getter in Getters) - getter.Text = "Client; " + getter.Client.Statistics.BytesAllocated + " bytes allocated"; - - while (NativeMethods.AppStillIdle) - { - foreach (ImageGetter getter in Getters) - getter.Heartbeat(); - System.Threading.Thread.Sleep(1); - } - } - - internal static void SpawnGetter(string host, NetPeerConfiguration copyConfig) - { - ImageGetter getter = new ImageGetter(host, copyConfig); - Getters.Add(getter); - getter.Show(); - } - } -} diff --git a/Samples/ImageClient/Properties/AssemblyInfo.cs b/Samples/ImageClient/Properties/AssemblyInfo.cs deleted file mode 100644 index 9465f55..0000000 --- a/Samples/ImageClient/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ImageClient")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("ImageClient")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("8dc39d59-b635-4296-bdab-3a18e2d9f425")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Samples/ImageClient/Properties/Resources.Designer.cs b/Samples/ImageClient/Properties/Resources.Designer.cs deleted file mode 100644 index 7afb00a..0000000 --- a/Samples/ImageClient/Properties/Resources.Designer.cs +++ /dev/null @@ -1,71 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:2.0.50727.4927 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace ImageClient.Properties -{ - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources - { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if ((resourceMan == null)) - { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ImageClient.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { - return resourceCulture; - } - set - { - resourceCulture = value; - } - } - } -} diff --git a/Samples/ImageClient/Properties/Resources.resx b/Samples/ImageClient/Properties/Resources.resx deleted file mode 100644 index ffecec8..0000000 --- a/Samples/ImageClient/Properties/Resources.resx +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Samples/ImageClient/Properties/Settings.Designer.cs b/Samples/ImageClient/Properties/Settings.Designer.cs deleted file mode 100644 index ff27b62..0000000 --- a/Samples/ImageClient/Properties/Settings.Designer.cs +++ /dev/null @@ -1,30 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:2.0.50727.4927 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace ImageClient.Properties -{ - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase - { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default - { - get - { - return defaultInstance; - } - } - } -} diff --git a/Samples/ImageClient/Properties/Settings.settings b/Samples/ImageClient/Properties/Settings.settings deleted file mode 100644 index abf36c5..0000000 --- a/Samples/ImageClient/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Samples/ImageServer/Form1.Designer.cs b/Samples/ImageServer/Form1.Designer.cs deleted file mode 100644 index 737777a..0000000 --- a/Samples/ImageServer/Form1.Designer.cs +++ /dev/null @@ -1,89 +0,0 @@ -namespace ImageServer -{ - partial class Form1 - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.button1 = new System.Windows.Forms.Button(); - this.button2 = new System.Windows.Forms.Button(); - this.richTextBox1 = new System.Windows.Forms.RichTextBox(); - this.SuspendLayout(); - // - // button1 - // - this.button1.Location = new System.Drawing.Point(253, 12); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(75, 23); - this.button1.TabIndex = 0; - this.button1.Text = "settings"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); - // - // button2 - // - this.button2.Location = new System.Drawing.Point(12, 12); - this.button2.Name = "button2"; - this.button2.Size = new System.Drawing.Size(235, 23); - this.button2.TabIndex = 1; - this.button2.Text = "Select image and start serving"; - this.button2.UseVisualStyleBackColor = true; - this.button2.Click += new System.EventHandler(this.button2_Click); - // - // richTextBox1 - // - this.richTextBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.richTextBox1.Location = new System.Drawing.Point(12, 41); - this.richTextBox1.Name = "richTextBox1"; - this.richTextBox1.Size = new System.Drawing.Size(469, 130); - this.richTextBox1.TabIndex = 2; - this.richTextBox1.Text = ""; - // - // Form1 - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(493, 183); - this.Controls.Add(this.richTextBox1); - this.Controls.Add(this.button2); - this.Controls.Add(this.button1); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.Name = "Form1"; - this.Text = "Server: Not running"; - this.ResumeLayout(false); - - } - - #endregion - - private System.Windows.Forms.Button button1; - private System.Windows.Forms.Button button2; - public System.Windows.Forms.RichTextBox richTextBox1; - } -} - diff --git a/Samples/ImageServer/Form1.cs b/Samples/ImageServer/Form1.cs deleted file mode 100644 index e4b0c65..0000000 --- a/Samples/ImageServer/Form1.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Windows.Forms; -using SamplesCommon; - -namespace ImageServer -{ - public partial class Form1 : Form - { - private NetPeerSettingsWindow m_settingsWindow; - - public Form1() - { - InitializeComponent(); - } - - private void button1_Click(object sender, EventArgs e) - { - if (m_settingsWindow == null) - { - m_settingsWindow = new NetPeerSettingsWindow("Image server settings", Program.Server); - m_settingsWindow.Show(); - } - else - { - m_settingsWindow.Close(); - m_settingsWindow = null; - } - } - - private void button2_Click(object sender, EventArgs e) - { - OpenFileDialog dlg = new OpenFileDialog(); - dlg.Filter = "Image files|*.png;*.jpg;*.jpeg"; - DialogResult res = dlg.ShowDialog(); - if (res != DialogResult.OK) - return; - Program.Start(dlg.FileName); - } - } -} diff --git a/Samples/ImageServer/Form1.resx b/Samples/ImageServer/Form1.resx deleted file mode 100644 index ff31a6d..0000000 --- a/Samples/ImageServer/Form1.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Samples/ImageServer/ImageServer.csproj b/Samples/ImageServer/ImageServer.csproj deleted file mode 100644 index c9d047e..0000000 --- a/Samples/ImageServer/ImageServer.csproj +++ /dev/null @@ -1,93 +0,0 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {36382EFB-BE9E-45B3-BEC8-E70F65CDF868} - WinExe - Properties - ImageServer - ImageServer - v3.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - 3.5 - - - - - - - - - Form - - - Form1.cs - - - - - Form1.cs - Designer - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - {FA245447-5F23-4AA1-BD5F-8D2DDF33CFBD} - Lidgren.Network - - - {773069DA-B66E-4667-ADCB-0D215AD8CF3E} - SamplesCommon - - - - - \ No newline at end of file diff --git a/Samples/ImageServer/Program.cs b/Samples/ImageServer/Program.cs deleted file mode 100644 index 283f92a..0000000 --- a/Samples/ImageServer/Program.cs +++ /dev/null @@ -1,172 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Windows.Forms; - -using Lidgren.Network; -using SamplesCommon; -using System.Drawing; - -namespace ImageServer -{ - static class Program - { - public static Form1 MainForm; - public static NetServer Server; - public static byte[] ImageData; - public static int ImageWidth, ImageHeight; - - [STAThread] - static void Main() - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - MainForm = new Form1(); - - // create a configuration, use identifier "ImageTransfer" - same as client - NetPeerConfiguration config = new NetPeerConfiguration("ImageTransfer"); - config.EnableMessageType(NetIncomingMessageType.ConnectionApproval); - config.EnableMessageType(NetIncomingMessageType.DiscoveryRequest); - - // listen on port 14242 - config.Port = 14242; - - Server = new NetServer(config); - - System.IO.File.Delete("C:\\tmp\\clientlog.txt"); - System.IO.File.Delete("C:\\tmp\\serverlog.txt"); - - Application.Idle += new EventHandler(AppLoop); - Application.Run(MainForm); - } - - static void AppLoop(object sender, EventArgs e) - { - NetIncomingMessage inc; - - MainForm.Text = "Server; " + Server.Statistics.BytesAllocated + " bytes allocated"; - - while (NativeMethods.AppStillIdle) - { - // read any pending messages - while ((inc = Server.WaitMessage(100)) != null) - { - switch (inc.MessageType) - { - case NetIncomingMessageType.DebugMessage: - case NetIncomingMessageType.VerboseDebugMessage: - case NetIncomingMessageType.WarningMessage: - case NetIncomingMessageType.ErrorMessage: - // just print any message - string str = inc.ReadString(); - NativeMethods.AppendText(MainForm.richTextBox1, str); - System.IO.File.AppendAllText("C:\\tmp\\serverlog.txt", str + Environment.NewLine); - break; - case NetIncomingMessageType.DiscoveryRequest: - NetOutgoingMessage dom = Server.CreateMessage(); - dom.Write("Kokosboll"); - Server.SendDiscoveryResponse(dom, inc.SenderEndpoint); - break; - case NetIncomingMessageType.ConnectionApproval: - - // Here we could check inc.SenderConnection.RemoteEndPoint, deny certain ip - - // check hail data - try - { - int a = inc.ReadInt32(); - string s = inc.ReadString(); - - if (a == 42 && s == "secret") - inc.SenderConnection.Approve(); - else - inc.SenderConnection.Deny("Bad approve data, go away!"); - } - catch (NetException) - { - inc.SenderConnection.Deny("Bad approve data, go away!"); - } - break; - case NetIncomingMessageType.StatusChanged: - NetConnectionStatus status = (NetConnectionStatus)inc.ReadByte(); - NativeMethods.AppendText(MainForm.richTextBox1, "New status: " + status + " (" + inc.ReadString() + ")"); - if (status == NetConnectionStatus.Connected) - { - // - // A client connected; send the entire image in chunks of 990 bytes - // - /* - uint seg = 0; - int ptr = 0; - while (ptr < ImageData.Length) - { - int l = ImageData.Length - ptr > 990 ? 990 : ImageData.Length - ptr; - NetOutgoingMessage om = Server.CreateMessage(l); - om.Write((ushort)ImageWidth); - om.Write((ushort)ImageHeight); - om.WriteVariableUInt32(seg++); - om.Write(ImageData, ptr, l); - ptr += 990; - - Server.SendMessage(om, inc.SenderConnection, NetDeliveryMethod.ReliableUnordered, 0); - } - */ - - NetOutgoingMessage om = Server.CreateMessage(ImageData.Length + 5); - - om.Write((ushort)ImageWidth); - om.Write((ushort)ImageHeight); - om.WriteVariableUInt32(0); - - // send entire as a large message that will be automatically fragmented by the library - om.Write(ImageData); - - Server.SendMessage(om, inc.SenderConnection, NetDeliveryMethod.ReliableOrdered, 0); - - // all messages will be sent before disconnect so we can call it here - // inc.SenderConnection.Disconnect("Bye bye now"); - } - break; - } - - // recycle message to avoid garbage - Server.Recycle(inc); - } - } - } - - public static void Start(string filename) - { - if (Server.Status != NetPeerStatus.NotRunning) - { - Server.Shutdown("Restarting"); - System.Threading.Thread.Sleep(100); - } - - Server.Start(); - - MainForm.Text = "Server: Running"; - - // get image size - Bitmap bm = Bitmap.FromFile(filename) as Bitmap; - ImageWidth = bm.Width; - ImageHeight = bm.Height; - - // extract color bytes - // very slow method, but small code size - ImageData = new byte[3 * ImageWidth * ImageHeight]; - int ptr = 0; - for (int y = 0; y < ImageHeight; y++) - { - for (int x = 0; x < ImageWidth; x++) - { - Color color = bm.GetPixel(x, y); - ImageData[ptr++] = color.R; - ImageData[ptr++] = color.G; - ImageData[ptr++] = color.B; - } - } - - bm.Dispose(); - } - } -} diff --git a/Samples/ImageServer/Properties/AssemblyInfo.cs b/Samples/ImageServer/Properties/AssemblyInfo.cs deleted file mode 100644 index 5b32b04..0000000 --- a/Samples/ImageServer/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ImageServer")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("ImageServer")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("4c8071cf-f3d6-4d3f-8937-944273b6fb40")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Samples/ImageServer/Properties/Resources.Designer.cs b/Samples/ImageServer/Properties/Resources.Designer.cs deleted file mode 100644 index 84d02b2..0000000 --- a/Samples/ImageServer/Properties/Resources.Designer.cs +++ /dev/null @@ -1,71 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:2.0.50727.4927 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace ImageServer.Properties -{ - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources - { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if ((resourceMan == null)) - { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ImageServer.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { - return resourceCulture; - } - set - { - resourceCulture = value; - } - } - } -} diff --git a/Samples/ImageServer/Properties/Resources.resx b/Samples/ImageServer/Properties/Resources.resx deleted file mode 100644 index ffecec8..0000000 --- a/Samples/ImageServer/Properties/Resources.resx +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Samples/ImageServer/Properties/Settings.Designer.cs b/Samples/ImageServer/Properties/Settings.Designer.cs deleted file mode 100644 index 4008204..0000000 --- a/Samples/ImageServer/Properties/Settings.Designer.cs +++ /dev/null @@ -1,30 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:2.0.50727.4927 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace ImageServer.Properties -{ - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase - { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default - { - get - { - return defaultInstance; - } - } - } -} diff --git a/Samples/ImageServer/Properties/Settings.settings b/Samples/ImageServer/Properties/Settings.settings deleted file mode 100644 index abf36c5..0000000 --- a/Samples/ImageServer/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Samples/ManyClients/Client.Designer.cs b/Samples/ManyClients/Client.Designer.cs deleted file mode 100644 index 099869d..0000000 --- a/Samples/ManyClients/Client.Designer.cs +++ /dev/null @@ -1,61 +0,0 @@ -namespace ManyClients -{ - partial class Client - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.button1 = new System.Windows.Forms.Button(); - this.SuspendLayout(); - // - // button1 - // - this.button1.Location = new System.Drawing.Point(82, 21); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(106, 23); - this.button1.TabIndex = 0; - this.button1.Text = "Send message"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); - // - // Client - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(264, 69); - this.Controls.Add(this.button1); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.Name = "Client"; - this.Text = "Client"; - this.ResumeLayout(false); - - } - - #endregion - - private System.Windows.Forms.Button button1; - } -} \ No newline at end of file diff --git a/Samples/ManyClients/Client.cs b/Samples/ManyClients/Client.cs deleted file mode 100644 index 3a63112..0000000 --- a/Samples/ManyClients/Client.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Windows.Forms; -using Lidgren.Network; - -namespace ManyClients -{ - public partial class Client : Form - { - private const double c_sendFrequency = 0.5; - - public NetClient Net; - - private double m_lastSent; - - public Client() - { - InitializeComponent(); - - NetPeerConfiguration config = new NetPeerConfiguration("many"); -#if DEBUG - config.SimulatedLoss = 0.02f; -#endif - Net = new NetClient(config); - Net.Start(); - Net.Connect("localhost", 14242); - } - - protected override void OnClosed(EventArgs e) - { - Net.Shutdown("closed"); - } - - internal void Shutdown() - { - Net.Shutdown("bye"); - } - - internal void Heartbeat() - { - NetIncomingMessage inc; - while ((inc = Net.ReadMessage()) != null) - { - switch (inc.MessageType) - { - case NetIncomingMessageType.StatusChanged: - NetConnectionStatus status = (NetConnectionStatus)inc.ReadByte(); - this.Text = status.ToString(); - break; - case NetIncomingMessageType.ErrorMessage: - this.Text = inc.ReadString(); - break; - } - } - - // send message? - if (NetTime.Now > m_lastSent + c_sendFrequency) - { - var om = Net.CreateMessage(); - om.Write("Hi!"); - Net.SendMessage(om, NetDeliveryMethod.ReliableOrdered); - m_lastSent = NetTime.Now; - - // also update title - this.Text = Net.Statistics.SentBytes + " bytes sent; " + Net.Statistics.ReceivedBytes + " bytes received"; - } - } - - private void button1_Click(object sender, EventArgs e) - { - var om = Net.CreateMessage(); - om.Write("Hi!"); - - Net.SendMessage(om, NetDeliveryMethod.ReliableOrdered); - } - } -} diff --git a/Samples/ManyClients/Client.resx b/Samples/ManyClients/Client.resx deleted file mode 100644 index ff31a6d..0000000 --- a/Samples/ManyClients/Client.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Samples/ManyClients/Form1.Designer.cs b/Samples/ManyClients/Form1.Designer.cs deleted file mode 100644 index 6681597..0000000 --- a/Samples/ManyClients/Form1.Designer.cs +++ /dev/null @@ -1,75 +0,0 @@ -namespace ManyClients -{ - partial class Form1 - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.label1 = new System.Windows.Forms.Label(); - this.button1 = new System.Windows.Forms.Button(); - this.SuspendLayout(); - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(12, 9); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(38, 13); - this.label1.TabIndex = 0; - this.label1.Text = "label1"; - // - // button1 - // - this.button1.Location = new System.Drawing.Point(63, 44); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(158, 41); - this.button1.TabIndex = 1; - this.button1.Text = "Create new client"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); - // - // Form1 - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(270, 97); - this.Controls.Add(this.button1); - this.Controls.Add(this.label1); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.Name = "Form1"; - this.Text = "Form1"; - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.Label label1; - private System.Windows.Forms.Button button1; - } -} - diff --git a/Samples/ManyClients/Form1.cs b/Samples/ManyClients/Form1.cs deleted file mode 100644 index 4a8dfd7..0000000 --- a/Samples/ManyClients/Form1.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Windows.Forms; - -namespace ManyClients -{ - public partial class Form1 : Form - { - public Form1() - { - InitializeComponent(); - } - - private void button1_Click(object sender, EventArgs e) - { - Program.CreateClient(); - } - } -} diff --git a/Samples/ManyClients/Form1.resx b/Samples/ManyClients/Form1.resx deleted file mode 100644 index ff31a6d..0000000 --- a/Samples/ManyClients/Form1.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Samples/ManyClients/ManyClients.csproj b/Samples/ManyClients/ManyClients.csproj deleted file mode 100644 index 9827081..0000000 --- a/Samples/ManyClients/ManyClients.csproj +++ /dev/null @@ -1,110 +0,0 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {A41772F5-F20F-408D-ABD1-5D1C144853C6} - WinExe - Properties - ManyClients - ManyClients - v3.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - 3.5 - - - 3.5 - - - 3.5 - - - - - - - - - - Form - - - Client.cs - - - Form - - - Form1.cs - - - - - Client.cs - Designer - - - Form1.cs - Designer - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - {FA245447-5F23-4AA1-BD5F-8D2DDF33CFBD} - Lidgren.Network - - - {773069DA-B66E-4667-ADCB-0D215AD8CF3E} - SamplesCommon - - - - - \ No newline at end of file diff --git a/Samples/ManyClients/Program.cs b/Samples/ManyClients/Program.cs deleted file mode 100644 index a2d8ba7..0000000 --- a/Samples/ManyClients/Program.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Windows.Forms; -using SamplesCommon; - -namespace ManyClients -{ - static class Program - { - public static List Clients; - - [STAThread] - static void Main() - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - - Clients = new List(); - - Application.Idle += new EventHandler(AppIdle); - Application.Run(new Form1()); - - foreach (var c in Clients) - c.Shutdown(); - } - - static void AppIdle(object sender, EventArgs e) - { - while (NativeMethods.AppStillIdle) - { - foreach (var c in Clients) - c.Heartbeat(); - System.Threading.Thread.Sleep(1); - } - } - - internal static void CreateClient() - { - Client client = new Client(); - client.Show(); - Clients.Add(client); - } - } -} diff --git a/Samples/ManyClients/Properties/AssemblyInfo.cs b/Samples/ManyClients/Properties/AssemblyInfo.cs deleted file mode 100644 index 2fee1ee..0000000 --- a/Samples/ManyClients/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ManyClients")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("ManyClients")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("140e8b00-0bb5-4e9e-847c-56ad106f01a4")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Samples/ManyClients/Properties/Resources.Designer.cs b/Samples/ManyClients/Properties/Resources.Designer.cs deleted file mode 100644 index 1dd11cf..0000000 --- a/Samples/ManyClients/Properties/Resources.Designer.cs +++ /dev/null @@ -1,71 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:2.0.50727.4927 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace ManyClients.Properties -{ - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources - { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if ((resourceMan == null)) - { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ManyClients.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { - return resourceCulture; - } - set - { - resourceCulture = value; - } - } - } -} diff --git a/Samples/ManyClients/Properties/Resources.resx b/Samples/ManyClients/Properties/Resources.resx deleted file mode 100644 index ffecec8..0000000 --- a/Samples/ManyClients/Properties/Resources.resx +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Samples/ManyClients/Properties/Settings.Designer.cs b/Samples/ManyClients/Properties/Settings.Designer.cs deleted file mode 100644 index f6c52b2..0000000 --- a/Samples/ManyClients/Properties/Settings.Designer.cs +++ /dev/null @@ -1,30 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:2.0.50727.4927 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace ManyClients.Properties -{ - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase - { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default - { - get - { - return defaultInstance; - } - } - } -} diff --git a/Samples/ManyClients/Properties/Settings.settings b/Samples/ManyClients/Properties/Settings.settings deleted file mode 100644 index abf36c5..0000000 --- a/Samples/ManyClients/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Samples/ManyServer/Form1.Designer.cs b/Samples/ManyServer/Form1.Designer.cs deleted file mode 100644 index e7439b3..0000000 --- a/Samples/ManyServer/Form1.Designer.cs +++ /dev/null @@ -1,64 +0,0 @@ -namespace ManyServer -{ - partial class Form1 - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.richTextBox1 = new System.Windows.Forms.RichTextBox(); - this.SuspendLayout(); - // - // richTextBox1 - // - this.richTextBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.richTextBox1.Location = new System.Drawing.Point(12, 168); - this.richTextBox1.Name = "richTextBox1"; - this.richTextBox1.Size = new System.Drawing.Size(808, 283); - this.richTextBox1.TabIndex = 0; - this.richTextBox1.Text = ""; - // - // Form1 - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(832, 463); - this.Controls.Add(this.richTextBox1); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.Name = "Form1"; - this.Text = "Form1"; - this.ResumeLayout(false); - - } - - #endregion - - public System.Windows.Forms.RichTextBox richTextBox1; - - } -} - diff --git a/Samples/ManyServer/Form1.cs b/Samples/ManyServer/Form1.cs deleted file mode 100644 index ead4937..0000000 --- a/Samples/ManyServer/Form1.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Windows.Forms; - -namespace ManyServer -{ - public partial class Form1 : Form - { - public Form1() - { - InitializeComponent(); - } - } -} diff --git a/Samples/ManyServer/Form1.resx b/Samples/ManyServer/Form1.resx deleted file mode 100644 index ff31a6d..0000000 --- a/Samples/ManyServer/Form1.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Samples/ManyServer/ManyServer.csproj b/Samples/ManyServer/ManyServer.csproj deleted file mode 100644 index 3333bcd..0000000 --- a/Samples/ManyServer/ManyServer.csproj +++ /dev/null @@ -1,99 +0,0 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {44EFFA4A-C7FC-4C45-B84D-F13A391EF4E7} - WinExe - Properties - ManyServer - ManyServer - v3.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - 3.5 - - - 3.5 - - - 3.5 - - - - - - - - - - Form - - - Form1.cs - - - - - Form1.cs - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - {FA245447-5F23-4AA1-BD5F-8D2DDF33CFBD} - Lidgren.Network - - - {773069DA-B66E-4667-ADCB-0D215AD8CF3E} - SamplesCommon - - - - - \ No newline at end of file diff --git a/Samples/ManyServer/Program.cs b/Samples/ManyServer/Program.cs deleted file mode 100644 index 858c8c1..0000000 --- a/Samples/ManyServer/Program.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Windows.Forms; - -using Lidgren.Network; -using SamplesCommon; - -namespace ManyServer -{ - static class Program - { - public static Form1 MainForm; - public static NetServer Server; - - [STAThread] - static void Main() - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - MainForm = new Form1(); - - NetPeerConfiguration config = new NetPeerConfiguration("many"); - config.Port = 14242; -#if DEBUG - config.SimulatedLoss = 0.02f; -#else - throw new Exception("Sample not relevant in RELEASE; statistics needed to make sense!"); -#endif - config.MaximumConnections = 64; - - Server = new NetServer(config); - Server.Start(); - - var swin = new NetPeerSettingsWindow("Server settings", Program.Server); - swin.Show(); - - Application.Idle += new EventHandler(AppLoop); - Application.Run(MainForm); - } - - static void AppLoop(object sender, EventArgs e) - { - NetIncomingMessage inc; - - while (NativeMethods.AppStillIdle) - { - // read any pending messages - while ((inc = Server.ReadMessage()) != null) - { - switch (inc.MessageType) - { - case NetIncomingMessageType.DebugMessage: - case NetIncomingMessageType.VerboseDebugMessage: - case NetIncomingMessageType.WarningMessage: - case NetIncomingMessageType.ErrorMessage: - // just print any message - string str = inc.ReadString(); - NativeMethods.AppendText(MainForm.richTextBox1, str); - break; - case NetIncomingMessageType.StatusChanged: - NetConnectionStatus status = (NetConnectionStatus)inc.ReadByte(); - string reason = inc.ReadString(); - NativeMethods.AppendText(MainForm.richTextBox1, NetUtility.ToHexString(inc.SenderConnection.RemoteUniqueIdentifier) + ": " + reason); - MainForm.Text = Server.ConnectionsCount + " connections"; - break; - case NetIncomingMessageType.Data: - string dstr = "Data from " + NetUtility.ToHexString(inc.SenderConnection.RemoteUniqueIdentifier) + ": " + inc.ReadString(); - //NativeMethods.AppendText(MainForm.richTextBox1, dstr); - - NetOutgoingMessage outMsg = Server.CreateMessage(); - outMsg.Write(dstr); - Server.SendMessage(outMsg, Server.Connections, NetDeliveryMethod.ReliableOrdered, 0); - break; - } - } - - System.Threading.Thread.Sleep(1); - } - } - } -} diff --git a/Samples/ManyServer/Properties/AssemblyInfo.cs b/Samples/ManyServer/Properties/AssemblyInfo.cs deleted file mode 100644 index f04c1e7..0000000 --- a/Samples/ManyServer/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ManyServer")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("ManyServer")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("21b31854-6021-4153-9363-aa7c23a9d997")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Samples/ManyServer/Properties/Resources.Designer.cs b/Samples/ManyServer/Properties/Resources.Designer.cs deleted file mode 100644 index f649427..0000000 --- a/Samples/ManyServer/Properties/Resources.Designer.cs +++ /dev/null @@ -1,71 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:2.0.50727.4927 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace ManyServer.Properties -{ - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources - { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if ((resourceMan == null)) - { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ManyServer.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { - return resourceCulture; - } - set - { - resourceCulture = value; - } - } - } -} diff --git a/Samples/ManyServer/Properties/Resources.resx b/Samples/ManyServer/Properties/Resources.resx deleted file mode 100644 index ffecec8..0000000 --- a/Samples/ManyServer/Properties/Resources.resx +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Samples/ManyServer/Properties/Settings.Designer.cs b/Samples/ManyServer/Properties/Settings.Designer.cs deleted file mode 100644 index 185da56..0000000 --- a/Samples/ManyServer/Properties/Settings.Designer.cs +++ /dev/null @@ -1,30 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:2.0.50727.4927 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace ManyServer.Properties -{ - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase - { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default - { - get - { - return defaultInstance; - } - } - } -} diff --git a/Samples/ManyServer/Properties/Settings.settings b/Samples/ManyServer/Properties/Settings.settings deleted file mode 100644 index abf36c5..0000000 --- a/Samples/ManyServer/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Samples/MasterServerSample/MSClient/MSClient.csproj b/Samples/MasterServerSample/MSClient/MSClient.csproj index ee849f5..5e6b93d 100644 --- a/Samples/MasterServerSample/MSClient/MSClient.csproj +++ b/Samples/MasterServerSample/MSClient/MSClient.csproj @@ -3,7 +3,7 @@ Debug AnyCPU - 9.0.30729 + 9.0.21022 2.0 {E4FBEFAB-0D5F-4108-BAA9-E796E14AD6B2} WinExe @@ -12,6 +12,10 @@ MSClient v3.5 512 + SAK + SAK + SAK + SAK true diff --git a/Samples/MasterServerSample/MSCommon/MSCommon.csproj b/Samples/MasterServerSample/MSCommon/MSCommon.csproj index 0da68ff..d5d279d 100644 --- a/Samples/MasterServerSample/MSCommon/MSCommon.csproj +++ b/Samples/MasterServerSample/MSCommon/MSCommon.csproj @@ -12,6 +12,10 @@ MSCommon v3.5 512 + SAK + SAK + SAK + SAK true diff --git a/Samples/MasterServerSample/MSServer/MSServer.csproj b/Samples/MasterServerSample/MSServer/MSServer.csproj index 4a4c4f3..345cd64 100644 --- a/Samples/MasterServerSample/MSServer/MSServer.csproj +++ b/Samples/MasterServerSample/MSServer/MSServer.csproj @@ -12,6 +12,10 @@ MSServer v3.5 512 + SAK + SAK + SAK + SAK true diff --git a/Samples/MasterServerSample/MasterServer/MasterServer.csproj b/Samples/MasterServerSample/MasterServer/MasterServer.csproj index ac03139..297ae50 100644 --- a/Samples/MasterServerSample/MasterServer/MasterServer.csproj +++ b/Samples/MasterServerSample/MasterServer/MasterServer.csproj @@ -3,7 +3,7 @@ Debug AnyCPU - 9.0.30729 + 9.0.21022 2.0 {47E2AC9A-F375-47A7-A4E6-9814D3A2954B} Exe @@ -12,6 +12,10 @@ MasterServer v3.5 512 + SAK + SAK + SAK + SAK true diff --git a/Samples/MasterServerSample/MasterServerSample.sln b/Samples/MasterServerSample/MasterServerSample.sln index 66b4b8f..16224f1 100644 --- a/Samples/MasterServerSample/MasterServerSample.sln +++ b/Samples/MasterServerSample/MasterServerSample.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MasterServer", "MasterServer\MasterServer.csproj", "{47E2AC9A-F375-47A7-A4E6-9814D3A2954B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lidgren.Network", "..\..\Lidgren.Network\Lidgren.Network.csproj", "{FA245447-5F23-4AA1-BD5F-8D2DDF33CFBD}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lidgren.Network", "..\..\Lidgren.Network\Lidgren.Network.csproj", "{AE483C29-042E-4226-BA52-D247CE7676DA}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSClient", "MSClient\MSClient.csproj", "{E4FBEFAB-0D5F-4108-BAA9-E796E14AD6B2}" EndProject @@ -12,6 +12,28 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSServer", "MSServer\MSServer.csproj", "{BBE12F3E-098F-4C13-842F-A52B86E2611A}" EndProject Global + GlobalSection(SourceCodeControl) = preSolution + SccNumberOfProjects = 6 + SccProjectName0 = Perforce\u0020Project + SccLocalPath0 = ..\\.. + SccProvider0 = MSSCCI:Perforce\u0020SCM + SccProjectFilePathRelativizedFromConnection0 = Samples\\MasterServerSample\\ + SccProjectUniqueName1 = ..\\..\\Lidgren.Network\\Lidgren.Network.csproj + SccLocalPath1 = ..\\.. + SccProjectFilePathRelativizedFromConnection1 = Lidgren.Network\\ + SccProjectUniqueName2 = MasterServer\\MasterServer.csproj + SccLocalPath2 = ..\\.. + SccProjectFilePathRelativizedFromConnection2 = Samples\\MasterServerSample\\MasterServer\\ + SccProjectUniqueName3 = MSClient\\MSClient.csproj + SccLocalPath3 = ..\\.. + SccProjectFilePathRelativizedFromConnection3 = Samples\\MasterServerSample\\MSClient\\ + SccProjectUniqueName4 = MSCommon\\MSCommon.csproj + SccLocalPath4 = ..\\.. + SccProjectFilePathRelativizedFromConnection4 = Samples\\MasterServerSample\\MSCommon\\ + SccProjectUniqueName5 = MSServer\\MSServer.csproj + SccLocalPath5 = ..\\.. + SccProjectFilePathRelativizedFromConnection5 = Samples\\MasterServerSample\\MSServer\\ + EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU @@ -21,10 +43,10 @@ Global {47E2AC9A-F375-47A7-A4E6-9814D3A2954B}.Debug|Any CPU.Build.0 = Debug|Any CPU {47E2AC9A-F375-47A7-A4E6-9814D3A2954B}.Release|Any CPU.ActiveCfg = Release|Any CPU {47E2AC9A-F375-47A7-A4E6-9814D3A2954B}.Release|Any CPU.Build.0 = Release|Any CPU - {FA245447-5F23-4AA1-BD5F-8D2DDF33CFBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FA245447-5F23-4AA1-BD5F-8D2DDF33CFBD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FA245447-5F23-4AA1-BD5F-8D2DDF33CFBD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FA245447-5F23-4AA1-BD5F-8D2DDF33CFBD}.Release|Any CPU.Build.0 = Release|Any CPU + {AE483C29-042E-4226-BA52-D247CE7676DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AE483C29-042E-4226-BA52-D247CE7676DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AE483C29-042E-4226-BA52-D247CE7676DA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AE483C29-042E-4226-BA52-D247CE7676DA}.Release|Any CPU.Build.0 = Release|Any CPU {E4FBEFAB-0D5F-4108-BAA9-E796E14AD6B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E4FBEFAB-0D5F-4108-BAA9-E796E14AD6B2}.Debug|Any CPU.Build.0 = Debug|Any CPU {E4FBEFAB-0D5F-4108-BAA9-E796E14AD6B2}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/Samples/SamplesCommon/NativeMethods.cs b/Samples/SamplesCommon/NativeMethods.cs deleted file mode 100644 index 64a3a01..0000000 --- a/Samples/SamplesCommon/NativeMethods.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Windows.Forms; - -namespace SamplesCommon -{ - public static class NativeMethods - { - [DllImport("user32.dll", CharSet = CharSet.Auto)] - public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam); - public const int WM_VSCROLL = 277; // Vertical scroll - public const int SB_BOTTOM = 7; // Scroll to bottom - - [StructLayout(LayoutKind.Sequential)] - public struct PeekMsg - { - public IntPtr hWnd; - public Message msg; - public IntPtr wParam; - public IntPtr lParam; - public uint time; - public System.Drawing.Point p; - } - - [System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously - [DllImport("User32.dll", CharSet = CharSet.Auto)] - public static extern bool PeekMessage(out PeekMsg msg, IntPtr hWnd, uint messageFilterMin, uint messageFilterMax, uint flags); - - public static bool AppStillIdle - { - get - { - PeekMsg msg; - return !PeekMessage(out msg, IntPtr.Zero, 0, 0, 0); - } - } - - public static void AppendText(RichTextBox box, string line) - { - try - { - box.AppendText(line + Environment.NewLine); - ScrollRichTextBox(box); - } - catch - { - } - } - - public static void ScrollRichTextBox(RichTextBox box) - { - if (box == null || box.IsDisposed || box.Disposing) - return; - SendMessage(box.Handle, WM_VSCROLL, (IntPtr)SB_BOTTOM, IntPtr.Zero); - } - } -} diff --git a/Samples/SamplesCommon/NetPeerSettingsWindow.Designer.cs b/Samples/SamplesCommon/NetPeerSettingsWindow.Designer.cs deleted file mode 100644 index 2d6823b..0000000 --- a/Samples/SamplesCommon/NetPeerSettingsWindow.Designer.cs +++ /dev/null @@ -1,362 +0,0 @@ -namespace SamplesCommon -{ - partial class NetPeerSettingsWindow - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.DebugCheckBox = new System.Windows.Forms.CheckBox(); - this.VerboseCheckBox = new System.Windows.Forms.CheckBox(); - this.groupBox1 = new System.Windows.Forms.GroupBox(); - this.label10 = new System.Windows.Forms.Label(); - this.label11 = new System.Windows.Forms.Label(); - this.ThrottleTextBox = new System.Windows.Forms.TextBox(); - this.label8 = new System.Windows.Forms.Label(); - this.label9 = new System.Windows.Forms.Label(); - this.textBox2 = new System.Windows.Forms.TextBox(); - this.label5 = new System.Windows.Forms.Label(); - this.label4 = new System.Windows.Forms.Label(); - this.textBox3 = new System.Windows.Forms.TextBox(); - this.label3 = new System.Windows.Forms.Label(); - this.label2 = new System.Windows.Forms.Label(); - this.label1 = new System.Windows.Forms.Label(); - this.LossTextBox = new System.Windows.Forms.TextBox(); - this.MinLatencyTextBox = new System.Windows.Forms.TextBox(); - this.groupBox2 = new System.Windows.Forms.GroupBox(); - this.label7 = new System.Windows.Forms.Label(); - this.label6 = new System.Windows.Forms.Label(); - this.textBox1 = new System.Windows.Forms.TextBox(); - this.button1 = new System.Windows.Forms.Button(); - this.groupBox3 = new System.Windows.Forms.GroupBox(); - this.StatisticsLabel = new System.Windows.Forms.Label(); - this.button2 = new System.Windows.Forms.Button(); - this.groupBox1.SuspendLayout(); - this.groupBox2.SuspendLayout(); - this.groupBox3.SuspendLayout(); - this.SuspendLayout(); - // - // DebugCheckBox - // - this.DebugCheckBox.AutoSize = true; - this.DebugCheckBox.Location = new System.Drawing.Point(6, 21); - this.DebugCheckBox.Name = "DebugCheckBox"; - this.DebugCheckBox.Size = new System.Drawing.Size(153, 17); - this.DebugCheckBox.TabIndex = 0; - this.DebugCheckBox.Text = "Display Debug messages"; - this.DebugCheckBox.UseVisualStyleBackColor = true; - this.DebugCheckBox.CheckedChanged += new System.EventHandler(this.DebugCheckBox_CheckedChanged); - // - // VerboseCheckBox - // - this.VerboseCheckBox.AutoSize = true; - this.VerboseCheckBox.Location = new System.Drawing.Point(6, 44); - this.VerboseCheckBox.Name = "VerboseCheckBox"; - this.VerboseCheckBox.Size = new System.Drawing.Size(197, 17); - this.VerboseCheckBox.TabIndex = 1; - this.VerboseCheckBox.Text = "Display Verbose debug messages"; - this.VerboseCheckBox.UseVisualStyleBackColor = true; - this.VerboseCheckBox.CheckedChanged += new System.EventHandler(this.VerboseCheckBox_CheckedChanged); - // - // groupBox1 - // - this.groupBox1.Controls.Add(this.label10); - this.groupBox1.Controls.Add(this.label11); - this.groupBox1.Controls.Add(this.ThrottleTextBox); - this.groupBox1.Controls.Add(this.label8); - this.groupBox1.Controls.Add(this.label9); - this.groupBox1.Controls.Add(this.textBox2); - this.groupBox1.Controls.Add(this.label5); - this.groupBox1.Controls.Add(this.label4); - this.groupBox1.Controls.Add(this.textBox3); - this.groupBox1.Controls.Add(this.label3); - this.groupBox1.Controls.Add(this.label2); - this.groupBox1.Controls.Add(this.label1); - this.groupBox1.Controls.Add(this.LossTextBox); - this.groupBox1.Controls.Add(this.MinLatencyTextBox); - this.groupBox1.Location = new System.Drawing.Point(291, 12); - this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(300, 142); - this.groupBox1.TabIndex = 2; - this.groupBox1.TabStop = false; - this.groupBox1.Text = "Simulation"; - // - // label10 - // - this.label10.AutoSize = true; - this.label10.Location = new System.Drawing.Point(163, 108); - this.label10.Name = "label10"; - this.label10.Size = new System.Drawing.Size(75, 13); - this.label10.TabIndex = 13; - this.label10.Text = "bytes/second"; - // - // label11 - // - this.label11.AutoSize = true; - this.label11.Location = new System.Drawing.Point(6, 108); - this.label11.Name = "label11"; - this.label11.Size = new System.Drawing.Size(47, 13); - this.label11.TabIndex = 12; - this.label11.Text = "Throttle"; - // - // ThrottleTextBox - // - this.ThrottleTextBox.Location = new System.Drawing.Point(103, 105); - this.ThrottleTextBox.Name = "ThrottleTextBox"; - this.ThrottleTextBox.Size = new System.Drawing.Size(54, 22); - this.ThrottleTextBox.TabIndex = 11; - this.ThrottleTextBox.TextChanged += new System.EventHandler(this.ThrottleTextBox_TextChanged); - // - // label8 - // - this.label8.AutoSize = true; - this.label8.Location = new System.Drawing.Point(163, 80); - this.label8.Name = "label8"; - this.label8.Size = new System.Drawing.Size(16, 13); - this.label8.TabIndex = 10; - this.label8.Text = "%"; - // - // label9 - // - this.label9.AutoSize = true; - this.label9.Location = new System.Drawing.Point(6, 80); - this.label9.Name = "label9"; - this.label9.Size = new System.Drawing.Size(61, 13); - this.label9.TabIndex = 9; - this.label9.Text = "Duplicates"; - // - // textBox2 - // - this.textBox2.Location = new System.Drawing.Point(103, 77); - this.textBox2.Name = "textBox2"; - this.textBox2.Size = new System.Drawing.Size(54, 22); - this.textBox2.TabIndex = 8; - this.textBox2.TextChanged += new System.EventHandler(this.textBox2_TextChanged); - // - // label5 - // - this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(163, 52); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(16, 13); - this.label5.TabIndex = 7; - this.label5.Text = "%"; - // - // label4 - // - this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(247, 24); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(21, 13); - this.label4.TabIndex = 6; - this.label4.Text = "ms"; - // - // textBox3 - // - this.textBox3.Location = new System.Drawing.Point(185, 21); - this.textBox3.Name = "textBox3"; - this.textBox3.Size = new System.Drawing.Size(54, 22); - this.textBox3.TabIndex = 5; - this.textBox3.TextChanged += new System.EventHandler(this.textBox3_TextChanged); - // - // label3 - // - this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(163, 24); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(18, 13); - this.label3.TabIndex = 4; - this.label3.Text = "to"; - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(6, 52); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(29, 13); - this.label2.TabIndex = 3; - this.label2.Text = "Loss"; - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(6, 24); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(91, 13); - this.label1.TabIndex = 2; - this.label1.Text = "One way latency"; - // - // LossTextBox - // - this.LossTextBox.Location = new System.Drawing.Point(103, 49); - this.LossTextBox.Name = "LossTextBox"; - this.LossTextBox.Size = new System.Drawing.Size(54, 22); - this.LossTextBox.TabIndex = 1; - this.LossTextBox.TextChanged += new System.EventHandler(this.LossTextBox_TextChanged); - // - // MinLatencyTextBox - // - this.MinLatencyTextBox.Location = new System.Drawing.Point(103, 21); - this.MinLatencyTextBox.Name = "MinLatencyTextBox"; - this.MinLatencyTextBox.Size = new System.Drawing.Size(54, 22); - this.MinLatencyTextBox.TabIndex = 0; - this.MinLatencyTextBox.TextChanged += new System.EventHandler(this.MinLatencyTextBox_TextChanged); - // - // groupBox2 - // - this.groupBox2.Controls.Add(this.label7); - this.groupBox2.Controls.Add(this.DebugCheckBox); - this.groupBox2.Controls.Add(this.VerboseCheckBox); - this.groupBox2.Controls.Add(this.label6); - this.groupBox2.Controls.Add(this.textBox1); - this.groupBox2.Location = new System.Drawing.Point(12, 12); - this.groupBox2.Name = "groupBox2"; - this.groupBox2.Size = new System.Drawing.Size(273, 142); - this.groupBox2.TabIndex = 3; - this.groupBox2.TabStop = false; - this.groupBox2.Text = "Settings"; - // - // label7 - // - this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(182, 70); - this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(21, 13); - this.label7.TabIndex = 10; - this.label7.Text = "ms"; - // - // label6 - // - this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(6, 70); - this.label6.Name = "label6"; - this.label6.Size = new System.Drawing.Size(84, 13); - this.label6.TabIndex = 9; - this.label6.Text = "Ping frequency"; - // - // textBox1 - // - this.textBox1.Location = new System.Drawing.Point(98, 67); - this.textBox1.Name = "textBox1"; - this.textBox1.Size = new System.Drawing.Size(76, 22); - this.textBox1.TabIndex = 8; - this.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged); - // - // button1 - // - this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.button1.Location = new System.Drawing.Point(494, 367); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(101, 36); - this.button1.TabIndex = 5; - this.button1.Text = "Refresh"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); - // - // groupBox3 - // - this.groupBox3.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.groupBox3.Controls.Add(this.StatisticsLabel); - this.groupBox3.Location = new System.Drawing.Point(12, 160); - this.groupBox3.Name = "groupBox3"; - this.groupBox3.Size = new System.Drawing.Size(579, 197); - this.groupBox3.TabIndex = 6; - this.groupBox3.TabStop = false; - this.groupBox3.Text = "Statistics"; - // - // StatisticsLabel - // - this.StatisticsLabel.AutoSize = true; - this.StatisticsLabel.Location = new System.Drawing.Point(6, 22); - this.StatisticsLabel.Name = "StatisticsLabel"; - this.StatisticsLabel.Size = new System.Drawing.Size(79, 13); - this.StatisticsLabel.TabIndex = 0; - this.StatisticsLabel.Text = "StatisticsLabel"; - // - // button2 - // - this.button2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.button2.Location = new System.Drawing.Point(389, 367); - this.button2.Name = "button2"; - this.button2.Size = new System.Drawing.Size(99, 36); - this.button2.TabIndex = 7; - this.button2.Text = "Close"; - this.button2.UseVisualStyleBackColor = true; - this.button2.Click += new System.EventHandler(this.button2_Click); - // - // NetPeerSettingsWindow - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(603, 411); - this.Controls.Add(this.button2); - this.Controls.Add(this.groupBox3); - this.Controls.Add(this.button1); - this.Controls.Add(this.groupBox2); - this.Controls.Add(this.groupBox1); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.Name = "NetPeerSettingsWindow"; - this.Text = "NetPeerSettingsWindow1"; - this.groupBox1.ResumeLayout(false); - this.groupBox1.PerformLayout(); - this.groupBox2.ResumeLayout(false); - this.groupBox2.PerformLayout(); - this.groupBox3.ResumeLayout(false); - this.groupBox3.PerformLayout(); - this.ResumeLayout(false); - - } - - #endregion - - private System.Windows.Forms.GroupBox groupBox1; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.GroupBox groupBox2; - private System.Windows.Forms.Label label5; - private System.Windows.Forms.Label label4; - private System.Windows.Forms.Label label3; - public System.Windows.Forms.CheckBox DebugCheckBox; - public System.Windows.Forms.CheckBox VerboseCheckBox; - public System.Windows.Forms.TextBox LossTextBox; - public System.Windows.Forms.TextBox MinLatencyTextBox; - public System.Windows.Forms.TextBox textBox3; - private System.Windows.Forms.Button button1; - private System.Windows.Forms.Label label7; - private System.Windows.Forms.Label label6; - private System.Windows.Forms.TextBox textBox1; - private System.Windows.Forms.GroupBox groupBox3; - public System.Windows.Forms.Label StatisticsLabel; - private System.Windows.Forms.Button button2; - private System.Windows.Forms.Label label8; - private System.Windows.Forms.Label label9; - public System.Windows.Forms.TextBox textBox2; - private System.Windows.Forms.Label label10; - private System.Windows.Forms.Label label11; - public System.Windows.Forms.TextBox ThrottleTextBox; - } -} \ No newline at end of file diff --git a/Samples/SamplesCommon/NetPeerSettingsWindow.cs b/Samples/SamplesCommon/NetPeerSettingsWindow.cs deleted file mode 100644 index 92dfb09..0000000 --- a/Samples/SamplesCommon/NetPeerSettingsWindow.cs +++ /dev/null @@ -1,158 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Text; -using System.Windows.Forms; -using System.Reflection; - -using Lidgren.Network; - -namespace SamplesCommon -{ - public partial class NetPeerSettingsWindow : Form - { - public NetPeer Peer; - public Timer timer; - - public NetPeerSettingsWindow(string title, NetPeer peer) - { - Peer = peer; - InitializeComponent(); - RefreshData(); - this.Text = title; - - // auto refresh now and then - timer = new Timer(); - timer.Interval = 250; - timer.Tick += new EventHandler(timer_Tick); - timer.Enabled = true; - } - - protected override void OnClosed(EventArgs e) - { - timer.Enabled = false; - base.OnClosed(e); - } - - void timer_Tick(object sender, EventArgs e) - { - RefreshData(); - } - - private void RefreshData() - { -#if DEBUG - LossTextBox.Text = ((int)(Peer.Configuration.SimulatedLoss * 100)).ToString(); - textBox2.Text = ((int)(Peer.Configuration.SimulatedDuplicatesChance * 100)).ToString(); - MinLatencyTextBox.Text = ((int)(Peer.Configuration.SimulatedMinimumLatency * 1000)).ToString(); - textBox3.Text = ((int)((Peer.Configuration.SimulatedMinimumLatency + Peer.Configuration.SimulatedRandomLatency) * 1000)).ToString(); -#else - LossTextBox.Text = "0"; - MinLatencyTextBox.Text = "0"; - textBox3.Text = "0"; - textBox2.Text = "0"; -#endif - DebugCheckBox.Checked = Peer.Configuration.IsMessageTypeEnabled(NetIncomingMessageType.DebugMessage); - VerboseCheckBox.Checked = Peer.Configuration.IsMessageTypeEnabled(NetIncomingMessageType.VerboseDebugMessage); - textBox1.Text = (Peer.Configuration.PingFrequency * 1000).ToString(); - ThrottleTextBox.Text = Peer.Configuration.ThrottleBytesPerSecond.ToString(); - - StringBuilder bdr = new StringBuilder(); - bdr.AppendLine(Peer.Statistics.ToString()); - - if (Peer.ConnectionsCount > 0) - { - NetConnection conn = Peer.Connections[0]; - bdr.AppendLine("Connection 0:"); - bdr.AppendLine("Average RTT: " + ((int)(conn.AverageRoundtripTime * 1000.0f)) + " ms"); - bdr.AppendLine("Last response: " + (int)(NetTime.Now - conn.Statistics.LastSendRespondedTo) + "s ago"); - bdr.AppendLine("Most sends: " + conn.Statistics.MostSends); - bdr.Append(conn.Statistics.ToString()); - } - - StatisticsLabel.Text = bdr.ToString(); - } - - private void DebugCheckBox_CheckedChanged(object sender, EventArgs e) - { - Peer.Configuration.SetMessageTypeEnabled(NetIncomingMessageType.DebugMessage, DebugCheckBox.Checked); - } - - private void VerboseCheckBox_CheckedChanged(object sender, EventArgs e) - { - Peer.Configuration.SetMessageTypeEnabled(NetIncomingMessageType.VerboseDebugMessage, VerboseCheckBox.Checked); - } - - private void LossTextBox_TextChanged(object sender, EventArgs e) - { -#if DEBUG - float ms; - if (Single.TryParse(LossTextBox.Text, out ms)) - Peer.Configuration.SimulatedLoss = (float)((double)ms / 100.0); -#endif - } - - private void textBox2_TextChanged(object sender, EventArgs e) - { -#if DEBUG - float ms; - if (Single.TryParse(textBox2.Text, out ms)) - Peer.Configuration.SimulatedDuplicatesChance = (float)((double)ms / 100.0); -#endif - } - - private void MinLatencyTextBox_TextChanged(object sender, EventArgs e) - { -#if DEBUG - float min; - if (float.TryParse(MinLatencyTextBox.Text, out min)) - Peer.Configuration.SimulatedMinimumLatency = (float)(min / 1000.0); - MinLatencyTextBox.Text = ((int)(Peer.Configuration.SimulatedMinimumLatency * 1000)).ToString(); -#endif - } - - private void textBox3_TextChanged(object sender, EventArgs e) - { -#if DEBUG - float max; - if (float.TryParse(textBox3.Text, out max)) - { - max = (float)((double)max / 1000.0); - float r = max - Peer.Configuration.SimulatedMinimumLatency; - if (r > 0) - { - Peer.Configuration.SimulatedRandomLatency = r; - double nm = (double)Peer.Configuration.SimulatedMinimumLatency + (double)Peer.Configuration.SimulatedRandomLatency; - textBox3.Text = ((int)(max * 1000)).ToString(); - } - } -#endif - } - - private void button1_Click(object sender, EventArgs e) - { - RefreshData(); - } - - private void textBox1_TextChanged(object sender, EventArgs e) - { - float d; - if (float.TryParse(textBox1.Text, out d)) - Peer.Configuration.PingFrequency = (float)(d / 1000.0); - } - - private void button2_Click(object sender, EventArgs e) - { - this.Close(); - } - - private void ThrottleTextBox_TextChanged(object sender, EventArgs e) - { - uint bps; - if (UInt32.TryParse(ThrottleTextBox.Text, out bps)) - Peer.Configuration.ThrottleBytesPerSecond = (int)bps; - } - - } -} diff --git a/Samples/SamplesCommon/NetPeerSettingsWindow.resx b/Samples/SamplesCommon/NetPeerSettingsWindow.resx deleted file mode 100644 index ff31a6d..0000000 --- a/Samples/SamplesCommon/NetPeerSettingsWindow.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Samples/SamplesCommon/Properties/AssemblyInfo.cs b/Samples/SamplesCommon/Properties/AssemblyInfo.cs deleted file mode 100644 index f121a97..0000000 --- a/Samples/SamplesCommon/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("SamplesCommon")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("SamplesCommon")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("7d1622f4-1dc7-4e94-8ec0-0a2a295dcf9a")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Samples/SamplesCommon/SamplesCommon.csproj b/Samples/SamplesCommon/SamplesCommon.csproj deleted file mode 100644 index 07b30da..0000000 --- a/Samples/SamplesCommon/SamplesCommon.csproj +++ /dev/null @@ -1,72 +0,0 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {773069DA-B66E-4667-ADCB-0D215AD8CF3E} - Library - Properties - SamplesCommon - SamplesCommon - v3.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - 3.5 - - - - - - - - - Form - - - NetPeerSettingsWindow.cs - - - - - - NetPeerSettingsWindow.cs - Designer - - - - - {FA245447-5F23-4AA1-BD5F-8D2DDF33CFBD} - Lidgren.Network - - - - - \ No newline at end of file diff --git a/UnitTests/BitVectorTests.cs b/UnitTests/BitVectorTests.cs index 57ac7d2..6bc9145 100644 --- a/UnitTests/BitVectorTests.cs +++ b/UnitTests/BitVectorTests.cs @@ -33,6 +33,7 @@ namespace UnitTests throw new NetException("bit vector fail 4"); } + /* v = new NetBitVector(9); v.Clear(); v.Set(3, true); @@ -61,6 +62,7 @@ namespace UnitTests if (v.ToString() != "[10000001000000000000000000000000000001]") throw new NetException("NetBitVector.RotateDown failed 5"); + */ Console.WriteLine("NetBitVector tests OK"); } diff --git a/UnitTests/EncryptionTests.cs b/UnitTests/EncryptionTests.cs index cadfcc3..a220bf4 100644 --- a/UnitTests/EncryptionTests.cs +++ b/UnitTests/EncryptionTests.cs @@ -57,90 +57,6 @@ namespace UnitTests throw new NetException("fail"); Console.WriteLine("Message encryption OK"); - - /* - Console.WriteLine("x = " + NetUtility.ToHexString(x)); - Console.WriteLine("v = " + NetUtility.ToHexString(verifier)); - Console.WriteLine(""); - - byte[] a = NetUtility.ToByteArray("d378cc3b09d12cfca5130e22df3f2f3bcf8ecfaddeae6af7f8b3e9f8b4fc9749"); // random - Console.WriteLine("a = " + NetUtility.ToHexString(a)); - byte[] A = NetSRP.ComputeClientChallenge(a); - Console.WriteLine("A = " + NetUtility.ToHexString(A)); - Console.WriteLine(""); - - byte[] b = NetUtility.ToByteArray("8394bdaebe1709124f4c1221707053440b30e270d457ece02818da63b53c2482"); // random - Console.WriteLine("b = " + NetUtility.ToHexString(b)); - byte[] B = NetSRP.ComputeServerChallenge(b, verifier); - Console.WriteLine("B = " + NetUtility.ToHexString(B)); - Console.WriteLine(""); - - byte[] u = NetSRP.ComputeU(A, B); - Console.WriteLine("u = " + NetUtility.ToHexString(u)); - - byte[] serverCompareValue; // Ss - serverCompareValue = NetSRP.ComputeServerCompareValue(A, verifier, u, b); - Console.WriteLine("Ss = " + NetUtility.ToHexString(serverCompareValue)); - - byte[] clientCompareValue; // Ss - clientCompareValue = NetSRP.ComputeClientCompareValue(B, x, u, a); - Console.WriteLine("Sc = " + NetUtility.ToHexString(clientCompareValue)); - */ - - // - // Pre-step: - // - // Server must store { Username, salt, verifier } - //byte[] salt = NetSRP.CreateRandomSalt(); - byte[] salt = NetUtility.ToByteArray("D016E5A43F0E2A1C8FF8"); - Console.WriteLine("s = " + NetUtility.ToHexString(salt)); - byte[] serverVerifier; - byte[] clientVerifier; - NetSRP.ComputePasswordVerifier("user", "password", salt, out serverVerifier, out clientVerifier); - // - Console.WriteLine("x = " + NetUtility.ToHexString(clientVerifier)); - Console.WriteLine("v = " + NetUtility.ToHexString(serverVerifier)); - - // CLIENT: - // Step 1: Client creates session private/public key pair - //byte[] clientPrivateKey = NetSRP.CreateRandomKey(); - byte[] clientPrivateKey = NetUtility.ToByteArray("EFDBE24D15173DC1FBA22A8D51077AE932841CB2DBA8B09B2CFC5543983B2C7A"); - Console.WriteLine("a = " + NetUtility.ToHexString(clientPrivateKey)); - byte[] clientPublicKey = NetSRP.ComputeClientPublicKey(clientPrivateKey); - // Step 2: Client sends username and client public key to server - - // SERVER: - // Step 3: Server creates session private/public key pair - //byte[] serverPrivateKey = NetSRP.CreateRandomKey(); - byte[] serverPrivateKey = NetUtility.ToByteArray("FB1D472CD89EAF323DB0F7DE80A01CC51DD5A0D1AFC8B79F3CF5A2FC88529ADC"); - Console.WriteLine("b = " + NetUtility.ToHexString(serverPrivateKey)); - byte[] serverPublicKey = NetSRP.ComputeServerPublicKey(serverPrivateKey, serverVerifier); - // Step 4: Server sends salt and server public key to client - - // CLIENT: - // Step 5: Client computes u and compare value - byte[] u = NetSRP.ComputeU(clientPublicKey, serverPublicKey); - Console.WriteLine("u = " + NetUtility.ToHexString(u)); - byte[] clientSessionKey = NetSRP.ComputeClientSessionKey(serverPublicKey, clientVerifier, u, clientPrivateKey); // this is where client proves it has x (and thus the password) - Console.WriteLine("Sc = " + NetUtility.ToHexString(clientSessionKey)); - - // SERVER: - // Step 6: Server computes u and compare value - // byte[] u = NetSRP.ComputeU(clientPublicKey, serverPublicKey); - byte[] serverSessionKey = NetSRP.ComputeServerSessionKey(clientPublicKey, serverVerifier, u, serverPrivateKey); - Console.WriteLine("Ss = " + NetUtility.ToHexString(serverSessionKey)); - - if (!NetUtility.CompareElements(clientSessionKey, serverSessionKey)) - Console.WriteLine("BAD!!!!!!!"); - - // Console.WriteLine("SRP test OK"); -/* -C ==> S C, A -C <== S s, B -C ==> S M[1] -C <== S M[2] - */ - } } } diff --git a/UnitTests/ReadWriteTests.cs b/UnitTests/ReadWriteTests.cs index 34731e7..ed95480 100644 --- a/UnitTests/ReadWriteTests.cs +++ b/UnitTests/ReadWriteTests.cs @@ -88,26 +88,7 @@ namespace UnitTests NetException.Assert(readTest.Number == 42); NetException.Assert(readTest.Name == "Hallon"); NetException.Assert(readTest.Age == 8.2f); - - msg = peer.CreateMessage(); - - System.IO.BinaryWriter br = new System.IO.BinaryWriter(msg); - - br.Write(true); - br.Write("hallon"); - br.Write((byte)42); - - int byteLen = msg.LengthBytes; - byte[] rbts = msg.PeekDataBuffer(); - - inc = Program.CreateIncomingMessage(rbts, msg.LengthBits); - - System.IO.BinaryReader rdr = new System.IO.BinaryReader(inc); - - bool one = rdr.ReadBoolean(); - string hallon = rdr.ReadString(); - byte fourtyTwo = rdr.ReadByte(); - + // test aligned WriteBytes/ReadBytes msg = peer.CreateMessage(); byte[] tmparr = new byte[] { 5, 6, 7, 8, 9 }; diff --git a/UnitTests/UnitTests.csproj b/UnitTests/UnitTests.csproj index 79afe54..ddf2e0a 100644 --- a/UnitTests/UnitTests.csproj +++ b/UnitTests/UnitTests.csproj @@ -5,13 +5,17 @@ AnyCPU 9.0.21022 2.0 - {9D7AC4F7-39CD-4BC8-8F45-00B67C196340} + {1515E834-F71E-4D9C-B601-74C709D3A0AE} Exe Properties UnitTests UnitTests v3.5 512 + SAK + SAK + SAK + SAK true @@ -32,19 +36,24 @@ + + 3.5 + + + + - - {FA245447-5F23-4AA1-BD5F-8D2DDF33CFBD} + {AE483C29-042E-4226-BA52-D247CE7676DA} Lidgren.Network