diff --git a/Lidgren.Network/NetConnection.cs b/Lidgren.Network/NetConnection.cs index e4a642d..29601f6 100644 --- a/Lidgren.Network/NetConnection.cs +++ b/Lidgren.Network/NetConnection.cs @@ -207,7 +207,16 @@ namespace Lidgren.Network if (ptr > 0 && (ptr + NetPeer.kMaxPacketHeaderSize + msgPayloadLength) > mtu) { // send packet and start new packet - m_owner.SendPacket(ptr, m_remoteEndpoint, numIncludedMessages); + 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; @@ -247,10 +256,19 @@ namespace Lidgren.Network if (ptr > 0) { - m_owner.SendPacket(ptr, m_remoteEndpoint, numIncludedMessages); - m_statistics.PacketSent(ptr, numIncludedMessages); - numIncludedMessages = 0; - m_throttleDebt += ptr; + 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; + } } } } diff --git a/Lidgren.Network/NetConstants.cs b/Lidgren.Network/NetConstants.cs index 62d6650..9c757bd 100644 --- a/Lidgren.Network/NetConstants.cs +++ b/Lidgren.Network/NetConstants.cs @@ -40,5 +40,7 @@ namespace Lidgren.Network /// Number of bytes added when message is really a fragment /// internal const int FragmentHeaderSize = 6; + + internal const string ConnResetMessage = "Connection was reset by remote host"; } } diff --git a/Lidgren.Network/NetEncryption.cs b/Lidgren.Network/NetEncryption.cs index dd592d9..ece805f 100644 --- a/Lidgren.Network/NetEncryption.cs +++ b/Lidgren.Network/NetEncryption.cs @@ -227,14 +227,73 @@ namespace Lidgren.Network string one = NetUtility.ToHexString(A); string two = NetUtility.ToHexString(B); - string compound = one + two.PadLeft(one.Length, '0'); + string compound = one.PadLeft(64, '0') + two.PadLeft(64, '0'); byte[] cc = NetUtility.ToByteArray(compound); + return NetSha.Hash(cc); + + //byte[] res = NetSha.Hash(cc); + //var resbig = new BigInteger(res); + //return BigInteger.Modulus(resbig, N).GetBytes(); + + /* + * + * SRP-3: u = first 32 bits (MSB) of SHA-1(B) + * SRP-6(a): u = SHA-1(A || B) +function srp_compute_u(Nv, av, bv) { + var ahex; + var bhex = String(bigInt2radix(bv, 16)); + var hashin = ""; + var utmp; + var nlen; + if(proto != "3") { + ahex = String(bigInt2radix(av, 16)); + if(proto == "6") { + if((ahex.length & 1) == 0) { + hashin += ahex; + } + else { + hashin += "0" + ahex; + } + } + else { // 6a requires left-padding + nlen = 2 * ((Nv.bitLength() + 7) >> 3); + hashin += nzero(nlen - ahex.length) + ahex; + } + } + if(proto == "3" || proto == "6") { + if((bhex.length & 1) == 0) { + hashin += bhex; + } + else { + hashin += "0" + bhex; + } + } + else { // 6a requires left-padding; nlen already set above + hashin += nzero(nlen - bhex.length) + bhex; + } + if(proto == "3") { + utmp = parseBigInt(calcSHA1Hex(hashin).substr(0, 8), 16); + } + else { + utmp = parseBigInt(calcSHA1Hex(hashin), 16); + } + if(utmp.compareTo(Nv) < 0) { + return utmp; + } + else { + return utmp.mod(Nv.subtract(one)); + } +} + + + */ + } /* - public static byte[] ComputeClientToken(byte[] serverChallenge, byte[] x, byte[] u - + public static byte[] ComputeClientToken(byte[] serverChallenge, byte[] x, byte[] u) + { // S = (B - kg^x) ^ (a + ux) (mod N) function srp_compute_client_S(BB, xx, uu, aa, kk) { @@ -243,7 +302,7 @@ function srp_compute_client_S(BB, xx, uu, aa, kk) { return btmp.modPow(xx.multiply(uu).add(aa), N); } */ - + public static byte[] ComputeServerToken(byte[] clientChallenge, byte[] verifier, byte[] u, byte[] serverChallengeSalt) { // S = (Av^u) ^ b (mod N) diff --git a/Lidgren.Network/NetIncomingMessage.cs b/Lidgren.Network/NetIncomingMessage.cs index 6be542e..253bcc2 100644 --- a/Lidgren.Network/NetIncomingMessage.cs +++ b/Lidgren.Network/NetIncomingMessage.cs @@ -130,6 +130,28 @@ 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; + retval.m_bitLength = m_bitLength; + retval.m_bitLength = m_bitLength; + + return retval; + } + public override string ToString() { return String.Format("[NetIncomingMessage {0}, {1}|{2}, {3} bits]", diff --git a/Lidgren.Network/NetPeer.Internal.cs b/Lidgren.Network/NetPeer.Internal.cs index 6d00348..53d21dc 100644 --- a/Lidgren.Network/NetPeer.Internal.cs +++ b/Lidgren.Network/NetPeer.Internal.cs @@ -230,6 +230,7 @@ namespace Lidgren.Network // int ptr = um.Encode(now, m_sendBuffer, 0, null); + bool connectionReset = false; if (recipient.Address.Equals(IPAddress.Broadcast)) { @@ -237,7 +238,7 @@ namespace Lidgren.Network try { m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); - SendPacket(ptr, recipient, 1); + SendPacket(ptr, recipient, 1, out connectionReset); } finally { @@ -247,8 +248,11 @@ namespace Lidgren.Network else { // send normally - SendPacket(ptr, recipient, 1); + SendPacket(ptr, recipient, 1, out connectionReset); } + + if (connectionReset) + LogWarning(NetConstants.ConnResetMessage); } // check if we need to reduce the recycled pool @@ -276,9 +280,9 @@ namespace Lidgren.Network catch (SocketException sx) { // no good response to this yet - if (sx.ErrorCode == 10054) + if (sx.SocketErrorCode == SocketError.ConnectionReset) { - // connection reset by peer, aka forcibly closed + // 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); return; @@ -288,7 +292,7 @@ namespace Lidgren.Network return; } - if (bytesReceived < 1) + if (bytesReceived < NetPeer.kMinPacketHeaderSize) return; // renew current time; we might have waited in Poll @@ -584,9 +588,13 @@ namespace Lidgren.Network int len = msg.Encode(now, m_sendBuffer, 0, conn); Interlocked.Decrement(ref msg.m_inQueueCount); - SendPacket(len, conn.m_remoteEndpoint, 1); + bool connectionReset; + SendPacket(len, conn.m_remoteEndpoint, 1, out connectionReset); Recycle(msg); + + if (connectionReset) + LogWarning("Connection was reset; remote host is not listening"); } } } \ No newline at end of file diff --git a/Lidgren.Network/NetPeer.LatencySimulation.cs b/Lidgren.Network/NetPeer.LatencySimulation.cs index 0828742..5023b12 100644 --- a/Lidgren.Network/NetPeer.LatencySimulation.cs +++ b/Lidgren.Network/NetPeer.LatencySimulation.cs @@ -37,8 +37,10 @@ namespace Lidgren.Network public IPEndPoint Target; } - internal void SendPacket(int numBytes, IPEndPoint target, int numMessages) + internal void SendPacket(int numBytes, IPEndPoint target, int numMessages, out bool connectionReset) { + connectionReset = false; + // simulate loss float loss = m_configuration.m_loss; if (loss > 0.0f) @@ -59,7 +61,7 @@ namespace Lidgren.Network { // no latency simulation //LogVerbose("Sending packet " + numBytes + " bytes"); - ActuallySendPacket(m_sendBuffer, numBytes, target); + ActuallySendPacket(m_sendBuffer, numBytes, target, out connectionReset); return; } @@ -92,26 +94,39 @@ namespace Lidgren.Network double now = NetTime.Now; + bool connectionReset; + RestartDelaySending: foreach (DelayedPacket p in m_delayedPackets) { if (now > p.DelayedUntil) { - ActuallySendPacket(p.Data, p.Data.Length, p.Target); + ActuallySendPacket(p.Data, p.Data.Length, p.Target, out connectionReset); m_delayedPackets.Remove(p); goto RestartDelaySending; } } } - internal void ActuallySendPacket(byte[] data, int numBytes, IPEndPoint target) + internal void ActuallySendPacket(byte[] data, int numBytes, IPEndPoint target, out bool connectionReset) { + connectionReset = false; try { int bytesSent = m_socket.SendTo(data, 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); @@ -122,7 +137,7 @@ namespace Lidgren.Network // // Release - just send the packet straight away // - internal void SendPacket(int numBytes, IPEndPoint target, int numMessages) + internal void SendPacket(int numBytes, IPEndPoint target, int numMessages, out bool connectionReset) { try { @@ -130,6 +145,16 @@ namespace Lidgren.Network 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); diff --git a/Lidgren.Network/NetPeerConfiguration.cs b/Lidgren.Network/NetPeerConfiguration.cs index 108b44a..8576339 100644 --- a/Lidgren.Network/NetPeerConfiguration.cs +++ b/Lidgren.Network/NetPeerConfiguration.cs @@ -27,7 +27,7 @@ namespace Lidgren.Network /// public sealed class NetPeerConfiguration { - private const string c_isLockedMessage = "You may not alter the NetPeerConfiguration after the NetPeer has been initialized!"; + private const string c_isLockedMessage = "You may not modify the NetPeerConfiguration after it has been used to initialize a NetPeer"; private bool m_isLocked; internal bool m_acceptIncomingConnections; diff --git a/UnitTests/EncryptionTests.cs b/UnitTests/EncryptionTests.cs index 2281fa2..b8eedd9 100644 --- a/UnitTests/EncryptionTests.cs +++ b/UnitTests/EncryptionTests.cs @@ -58,16 +58,16 @@ namespace UnitTests Console.WriteLine("Message encryption OK"); - byte[] salt = NetUtility.ToByteArray("e6fb7e23f001f3e6c081"); // s + byte[] salt = NetUtility.ToByteArray("62191568b7a1aa18f8eb"); // s byte[] verifier = NetSRP.ComputePasswordVerifier("user", "password", salt); Console.WriteLine("v = " + NetUtility.ToHexString(verifier)); - byte[] a = NetUtility.ToByteArray("3b6485358d1721cb438cb7d0b3c5f8f46186d43e1c47db7cd8aa80e19760e409"); + byte[] a = NetUtility.ToByteArray("129aac7ce0be45ab5f65ec0c6879222386c32177cb4024fe7ad593341c0a5085"); byte[] A = NetSRP.ComputeClientChallenge(a); Console.WriteLine("A = " + NetUtility.ToHexString(A)); - byte[] b = NetUtility.ToByteArray("fc17d424ce73a4c73e8fedfb25839e9917e861bc5253fff65697f81c75a87ea3"); + byte[] b = NetUtility.ToByteArray("cdbe8cec49e33c78c0b434be67fa2fdb7646776e757bcf59fad51bbbee0d53a1"); Console.WriteLine("b = " + NetUtility.ToHexString(b)); byte[] B = NetSRP.ComputeServerChallenge(b, verifier); Console.WriteLine("B = " + NetUtility.ToHexString(B));