From 38bb13b3a76e1c1769fa78815242c5cf18547b1f Mon Sep 17 00:00:00 2001 From: lidgren Date: Wed, 11 Aug 2010 18:34:15 +0000 Subject: [PATCH] initializing network (including binding to socket) moved out from network thread, enabling catching of exceptions ConnectionReset on reading handled properly (by disconnecting) when only one connection readonly added to various members --- Lidgren.Network/NetConnection.Handshake.cs | 2 +- Lidgren.Network/NetConnection.Reliability.cs | 16 +-- Lidgren.Network/NetConnection.cs | 16 ++- Lidgren.Network/NetEncryption.cs | 6 +- Lidgren.Network/NetIncomingMessage.Read.cs | 2 +- Lidgren.Network/NetPeer.ConnectionApproval.cs | 6 + Lidgren.Network/NetPeer.Internal.cs | 112 ++++++++---------- Lidgren.Network/NetPeer.Recycling.cs | 6 +- Lidgren.Network/NetPeer.cs | 6 +- Samples/ChatClient/Program.cs | 2 +- Samples/ChatServer/Program.cs | 2 +- 11 files changed, 83 insertions(+), 93 deletions(-) diff --git a/Lidgren.Network/NetConnection.Handshake.cs b/Lidgren.Network/NetConnection.Handshake.cs index 6cb5679..c087a15 100644 --- a/Lidgren.Network/NetConnection.Handshake.cs +++ b/Lidgren.Network/NetConnection.Handshake.cs @@ -149,7 +149,7 @@ namespace Lidgren.Network return; } - private void FinishDisconnect() + internal void FinishDisconnect() { m_owner.VerifyNetworkThread(); diff --git a/Lidgren.Network/NetConnection.Reliability.cs b/Lidgren.Network/NetConnection.Reliability.cs index d595cec..a3c84bf 100644 --- a/Lidgren.Network/NetConnection.Reliability.cs +++ b/Lidgren.Network/NetConnection.Reliability.cs @@ -25,8 +25,8 @@ namespace Lidgren.Network { public partial class NetConnection { - private int[] m_nextSendSequenceNumber; - private ushort[] m_lastReceivedSequenced; + private readonly int[] m_nextSendSequenceNumber; + private readonly ushort[] m_lastReceivedSequenced; internal readonly List m_unackedSends = new List(); @@ -57,17 +57,7 @@ namespace Lidgren.Network } return retval; } - - private void 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; - } - + internal ushort GetSendSequenceNumber(NetMessageType mtp) { if (mtp < NetMessageType.UserSequenced) diff --git a/Lidgren.Network/NetConnection.cs b/Lidgren.Network/NetConnection.cs index dc0b2e7..6f7b187 100644 --- a/Lidgren.Network/NetConnection.cs +++ b/Lidgren.Network/NetConnection.cs @@ -38,12 +38,12 @@ namespace Lidgren.Network internal NetConnectionStatus m_visibleStatus; private double m_lastSentUnsentMessages; private float m_throttleDebt; - private NetPeerConfiguration m_peerConfiguration; + private readonly NetPeerConfiguration m_peerConfiguration; internal NetConnectionStatistics m_statistics; private int m_lesserHeartbeats; private int m_nextFragmentGroupId; internal long m_remoteUniqueIdentifier; - private Dictionary m_fragmentGroups; + private readonly Dictionary m_fragmentGroups; private int m_handshakeAttempts; internal PendingConnectionStatus m_pendingStatus = PendingConnectionStatus.NotPending; @@ -99,7 +99,13 @@ namespace Lidgren.Network m_lastSendRespondedTo = now; m_statistics = new NetConnectionStatistics(this); - InitializeReliability(); + //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; } // run on network thread @@ -286,6 +292,7 @@ namespace Lidgren.Network } } + // when sending disconnect we can finish our own disconnect if (send.MessageType == NetMessageType.Library && msg.m_libType == NetMessageLibraryType.Disconnect) { FinishDisconnect(); @@ -706,6 +713,9 @@ namespace Lidgren.Network m_owner.LogVerbose("Disconnect requested for " + this); m_disconnectByeMessage = byeMessage; + if (m_status != NetConnectionStatus.Disconnected && m_status != NetConnectionStatus.None) + SetStatus(NetConnectionStatus.Disconnecting, byeMessage); + // loosen up throttling m_throttleDebt = -m_owner.m_configuration.m_throttlePeakBytes; diff --git a/Lidgren.Network/NetEncryption.cs b/Lidgren.Network/NetEncryption.cs index 482cf36..8e004d7 100644 --- a/Lidgren.Network/NetEncryption.cs +++ b/Lidgren.Network/NetEncryption.cs @@ -216,14 +216,14 @@ namespace Lidgren.Network /// public static byte[] ComputeClientPublicKey(byte[] clientPrivateKey) // a { - BigInteger salt = new BigInteger(clientPrivateKey); + BigInteger a = new BigInteger(clientPrivateKey); - BigInteger retval = g.ModPow(salt, N); + BigInteger retval = g.ModPow(a, N); string gs = NetUtility.ToHexString(g.GetBytes()); - Console.WriteLine("SALT: " + NetUtility.ToHexString(salt.GetBytes())); + Console.WriteLine("a: " + NetUtility.ToHexString(a.GetBytes())); Console.WriteLine("A: " + NetUtility.ToHexString(retval.GetBytes())); return retval.GetBytes(); diff --git a/Lidgren.Network/NetIncomingMessage.Read.cs b/Lidgren.Network/NetIncomingMessage.Read.cs index 297f8a5..d652dd0 100644 --- a/Lidgren.Network/NetIncomingMessage.Read.cs +++ b/Lidgren.Network/NetIncomingMessage.Read.cs @@ -28,7 +28,7 @@ namespace Lidgren.Network { private const string c_readOverflowError = "Trying to read past the buffer size - likely caused by mismatching Write/Reads, different size or order."; - private static Dictionary s_readMethods; + private static readonly Dictionary s_readMethods; private int m_readPosition; diff --git a/Lidgren.Network/NetPeer.ConnectionApproval.cs b/Lidgren.Network/NetPeer.ConnectionApproval.cs index f5160b9..8436bfc 100644 --- a/Lidgren.Network/NetPeer.ConnectionApproval.cs +++ b/Lidgren.Network/NetPeer.ConnectionApproval.cs @@ -64,6 +64,8 @@ namespace Lidgren.Network { LogWarning("Pending connection still in pending state after 10 seconds; forgot to Approve/Deny?"); m_pendingConnections.Remove(conn); + if (m_pendingConnections.Count < 1) + m_pendingConnections = null; return; } break; @@ -71,12 +73,16 @@ namespace Lidgren.Network // accept connection AcceptConnection(conn); m_pendingConnections.Remove(conn); + if (m_pendingConnections.Count < 1) + m_pendingConnections = null; return; case PendingConnectionStatus.Denied: // send disconnected NetOutgoingMessage bye = CreateLibraryMessage(NetMessageLibraryType.Disconnect, conn.m_pendingDenialReason); SendUnconnectedLibrary(bye, conn.m_remoteEndpoint); m_pendingConnections.Remove(conn); + if (m_pendingConnections.Count < 1) + m_pendingConnections = null; return; } } diff --git a/Lidgren.Network/NetPeer.Internal.cs b/Lidgren.Network/NetPeer.Internal.cs index 782b01b..63d4542 100644 --- a/Lidgren.Network/NetPeer.Internal.cs +++ b/Lidgren.Network/NetPeer.Internal.cs @@ -70,12 +70,11 @@ namespace Lidgren.Network // // Network loop // - private void Run() + private void InitializeNetwork() { // // Initialize // - VerifyNetworkThread(); InitializeRecycling(); @@ -94,8 +93,7 @@ namespace Lidgren.Network // random bytes is better than nothing NetRandom.Instance.NextBytes(m_macAddressBytes); #endif - - LogDebug("Network thread started"); + LogDebug("Initializing Network"); lock (m_initializeLock) { @@ -106,77 +104,50 @@ namespace Lidgren.Network // bind to socket IPEndPoint iep = null; - try - { - iep = new IPEndPoint(m_configuration.LocalAddress, m_configuration.Port); - EndPoint ep = (EndPoint)iep; - m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - m_socket.ReceiveBufferSize = m_configuration.ReceiveBufferSize; - m_socket.SendBufferSize = m_configuration.SendBufferSize; - m_socket.Blocking = false; - m_socket.Bind(ep); + iep = new IPEndPoint(m_configuration.LocalAddress, m_configuration.Port); + EndPoint ep = (EndPoint)iep; - IPEndPoint boundEp = m_socket.LocalEndPoint as IPEndPoint; - LogDebug("Socket bound to " + boundEp + ": " + m_socket.IsBound); + m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + m_socket.ReceiveBufferSize = m_configuration.ReceiveBufferSize; + m_socket.SendBufferSize = m_configuration.SendBufferSize; + m_socket.Blocking = false; + m_socket.Bind(ep); - m_listenPort = boundEp.Port; + IPEndPoint boundEp = m_socket.LocalEndPoint as IPEndPoint; + LogDebug("Socket bound to " + boundEp + ": " + m_socket.IsBound); - int first = (pa == null ? this.GetHashCode() : pa.GetHashCode()); - int second = boundEp.GetHashCode(); + m_listenPort = boundEp.Port; - 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); + int first = (pa == null ? this.GetHashCode() : pa.GetHashCode()); + int second = boundEp.GetHashCode(); - m_receiveBuffer = new byte[m_configuration.ReceiveBufferSize]; - m_sendBuffer = new byte[m_configuration.SendBufferSize]; + 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); - // only set Running if everything succeeds - m_status = NetPeerStatus.Running; + m_receiveBuffer = new byte[m_configuration.ReceiveBufferSize]; + m_sendBuffer = new byte[m_configuration.SendBufferSize]; - LogVerbose("Initialization done"); - } -#if DEBUG - catch(Exception) - { - throw; - } -#else - catch (SocketException sex) - { - // catastrophic failure; we can't know what's been initialized, try to back out - m_status = NetPeerStatus.NotRunning; + LogVerbose("Initialization done"); - if (sex.SocketErrorCode == SocketError.AddressAlreadyInUse) - LogError("Failed to bind to port " + (iep == null ? "Null" : iep.ToString()) + " - Address already in use!"); - else - LogError(sex.Message); - LogError("Lidgren could not initialize properly; please call Start() again"); - - // exit thread - return; - } - catch (Exception ex) - { - // catastrophic failure; we can't know what's been initialized, try to back out - m_status = NetPeerStatus.NotRunning; - - LogError(ex.Message); - LogError("Lidgren could not initialize properly; please call Start() again"); - - // exit thread - return; - } -#endif + // only set Running if everything succeeds + m_status = NetPeerStatus.Running; } + } + + private void NetworkLoop() + { + VerifyNetworkThread(); + + LogDebug("Network thread started"); // // Network loop @@ -329,6 +300,17 @@ namespace Lidgren.Network // 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 == 1) + { + // 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(); + } + } + return; } diff --git a/Lidgren.Network/NetPeer.Recycling.cs b/Lidgren.Network/NetPeer.Recycling.cs index 7dbf768..674b9b9 100644 --- a/Lidgren.Network/NetPeer.Recycling.cs +++ b/Lidgren.Network/NetPeer.Recycling.cs @@ -26,9 +26,9 @@ namespace Lidgren.Network { internal int m_storedBytes; private int m_maxStoredBytes; - private List m_storagePool = new List(); - private NetQueue m_incomingMessagesPool = new NetQueue(16); - private NetQueue m_outgoingMessagesPool = new NetQueue(16); + private readonly List m_storagePool = new List(); + private readonly NetQueue m_incomingMessagesPool = new NetQueue(16); + private readonly NetQueue m_outgoingMessagesPool = new NetQueue(16); private void InitializeRecycling() { diff --git a/Lidgren.Network/NetPeer.cs b/Lidgren.Network/NetPeer.cs index 46161bb..b301cd1 100644 --- a/Lidgren.Network/NetPeer.cs +++ b/Lidgren.Network/NetPeer.cs @@ -140,14 +140,16 @@ namespace Lidgren.Network m_configuration.VerifyAndLock(); + InitializeNetwork(); + // start network thread - m_networkThread = new Thread(new ThreadStart(Run)); + m_networkThread = new Thread(new ThreadStart(NetworkLoop)); m_networkThread.Name = "Lidgren network thread"; m_networkThread.IsBackground = true; m_networkThread.Start(); // allow some time for network thread to start up in case they call Connect() immediately - Thread.Sleep(3); + Thread.Sleep(10); } /// diff --git a/Samples/ChatClient/Program.cs b/Samples/ChatClient/Program.cs index 89f6f48..f87686f 100644 --- a/Samples/ChatClient/Program.cs +++ b/Samples/ChatClient/Program.cs @@ -64,7 +64,7 @@ namespace ChatClient NetOutgoingMessage om = Client.CreateMessage(); om.WriteAllFields(cm); - Client.SendMessage(om, NetDeliveryMethod.ReliableOrdered, 8); + Client.SendMessage(om, NetDeliveryMethod.ReliableOrdered, 1); } static void AppLoop(object sender, EventArgs e) diff --git a/Samples/ChatServer/Program.cs b/Samples/ChatServer/Program.cs index de90af4..320d195 100644 --- a/Samples/ChatServer/Program.cs +++ b/Samples/ChatServer/Program.cs @@ -79,7 +79,7 @@ namespace ChatServer NetOutgoingMessage om = Server.CreateMessage(); om.WriteAllProperties(cm, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); - Display("Forwarding text from " + cm.Sender + " to all clients: " + cm.Text); + Display("Forwarding text from " + cm.Sender + " (seqchan " + msg.SequenceChannel + ") to all clients: " + cm.Text); Server.SendMessage(om, Server.Connections, NetDeliveryMethod.ReliableOrdered, 0); break;