Unstable 1.1.14.0

This commit is contained in:
Markus Isberg
2023-10-02 16:43:54 +03:00
parent 94f5a93a0c
commit cf8f0de659
606 changed files with 21906 additions and 11456 deletions
+201 -203
View File
@@ -69,15 +69,8 @@ namespace Lidgren.Network
return;
// remove all callbacks regardless of sync context
RestartRemoveCallbacks:
for (int i = 0; i < m_receiveCallbacks.Count; i++)
{
if (m_receiveCallbacks[i].Item2.Equals(callback))
{
m_receiveCallbacks.RemoveAt(i);
goto RestartRemoveCallbacks;
}
}
m_receiveCallbacks.RemoveAll(tuple => tuple.Item2.Equals(callback));
if (m_receiveCallbacks.Count < 1)
m_receiveCallbacks = null;
}
@@ -123,49 +116,55 @@ namespace Lidgren.Network
}
m_lastSocketBind = now;
if (m_socket == null)
using (var mutex = new Mutex(false, "Global\\lidgrenSocketBind"))
{
try
{
m_socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
mutex.WaitOne();
if (m_socket == null)
m_socket = new Socket(m_configuration.LocalAddress.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
if (reBind)
m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, (int)1);
m_socket.ReceiveBufferSize = m_configuration.ReceiveBufferSize;
m_socket.SendBufferSize = m_configuration.SendBufferSize;
m_socket.Blocking = false;
if (m_configuration.DualStack)
{
if (m_configuration.LocalAddress.AddressFamily != AddressFamily.InterNetworkV6)
{
LogWarning("Configuration specifies Dual Stack but does not use IPv6 local address; Dual stack will not work.");
}
else
{
m_socket.DualMode = true;
}
}
var ep = (EndPoint)new NetEndPoint(m_configuration.LocalAddress, reBind ? m_listenPort : m_configuration.Port);
m_socket.Bind(ep);
try
{
const uint IOC_IN = 0x80000000;
const uint IOC_VENDOR = 0x18000000;
uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
m_socket.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
}
catch
{
// ignore; SIO_UDP_CONNRESET not supported on this platform
}
}
catch (SocketException socketException)
finally
{
if (socketException.SocketErrorCode == SocketError.AddressFamilyNotSupported)
{
// Fall back to IPv4 if IPv6 is unsupported
m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
}
else
{
throw;
}
mutex.ReleaseMutex();
}
}
if (reBind)
m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, (int)1);
m_socket.ReceiveBufferSize = m_configuration.ReceiveBufferSize;
m_socket.SendBufferSize = m_configuration.SendBufferSize;
m_socket.Blocking = false;
if (m_socket.AddressFamily == AddressFamily.InterNetworkV6) { m_socket.DualMode = m_configuration.UseDualModeSockets; }
var ep = (EndPoint)new NetEndPoint(m_configuration.LocalAddress.MapToFamily(m_socket.AddressFamily), reBind ? m_listenPort : m_configuration.Port);
m_socket.Bind(ep);
try
{
const uint IOC_IN = 0x80000000;
const uint IOC_VENDOR = 0x18000000;
uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
m_socket.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
}
catch
{
// ignore; SIO_UDP_CONNRESET not supported on this platform
}
var boundEp = m_socket.LocalEndPoint as NetEndPoint;
LogDebug("Socket bound to " + boundEp + ": " + m_socket.IsBound);
m_listenPort = boundEp.Port;
@@ -269,7 +268,7 @@ namespace Lidgren.Network
Heartbeat();
NetUtility.Sleep(10);
lock (m_initializeLock)
{
try
@@ -425,176 +424,175 @@ namespace Lidgren.Network
// update now
now = NetTime.Now;
do
try
{
do
{
ReceiveSocketData(now);
} while (m_socket.Available > 0);
}
catch (SocketException sx)
{
switch (sx.SocketErrorCode)
{
case 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?!
// So, what to do?
LogWarning("ConnectionReset");
return;
case SocketError.NotConnected:
// socket is unbound; try to rebind it (happens on mobile when process goes to sleep)
BindSocket(true);
return;
default:
LogWarning("Socket exception: " + sx.ToString());
return;
}
}
}
private void ReceiveSocketData(double now)
{
int bytesReceived = m_socket.ReceiveFrom(m_receiveBuffer, 0, m_receiveBuffer.Length, SocketFlags.None, ref m_senderRemote);
if (bytesReceived < NetConstants.HeaderByteSize)
return;
//LogVerbose("Received " + bytesReceived + " bytes");
var ipsender = (NetEndPoint)m_senderRemote;
if (m_upnp != null && now < m_upnp.m_discoveryResponseDeadline && bytesReceived > 32)
{
int bytesReceived = 0;
try
// is this an UPnP response?
string resp = System.Text.Encoding.UTF8.GetString(m_receiveBuffer, 0, bytesReceived);
if (resp.Contains("upnp:rootdevice") || resp.Contains("UPnP/1.0"))
{
if (m_senderRemote is IPEndPoint ipEndpoint && ipEndpoint.AddressFamily != m_socket.AddressFamily)
{
m_senderRemote = ipEndpoint.MapToFamily(m_socket.AddressFamily);
}
bytesReceived = m_socket.ReceiveFrom(m_receiveBuffer, 0, m_receiveBuffer.Length, SocketFlags.None, ref m_senderRemote);
}
catch (SocketException sx)
{
switch (sx.SocketErrorCode)
{
case 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?!
// So, what to do?
LogWarning("ConnectionReset");
return;
case SocketError.NotConnected:
// socket is unbound; try to rebind it (happens on mobile when process goes to sleep)
BindSocket(true);
return;
default:
LogWarning("Socket exception: " + sx.ToString());
return;
}
}
if (bytesReceived < NetConstants.HeaderByteSize)
return;
//LogVerbose("Received " + bytesReceived + " bytes");
var ipsender = (NetEndPoint)m_senderRemote;
if (m_upnp != null && now < m_upnp.m_discoveryResponseDeadline && bytesReceived > 32)
{
// is this an UPnP response?
string resp = System.Text.Encoding.UTF8.GetString(m_receiveBuffer, 0, bytesReceived);
if (resp.Contains("upnp:rootdevice") || resp.Contains("UPnP/1.0"))
{
try
{
resp = resp.Substring(resp.ToLower().IndexOf("location:") + 9);
resp = resp.Substring(0, resp.IndexOf("\r")).Trim();
m_upnp.ExtractServiceUrl(resp);
return;
}
catch (Exception ex)
{
LogDebug("Failed to parse UPnP response: " + ex.ToString());
// don't try to parse this packet further
return;
}
}
}
NetConnection sender = null;
m_connectionLookup.TryGetValue(ipsender, out sender);
//
// parse packet into messages
//
int numMessages = 0;
int numFragments = 0;
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
numMessages++;
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));
if (isFragment)
numFragments++;
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 (tp >= NetMessageType.Unused1 && tp <= NetMessageType.Unused29)
{
ThrowOrLog("Unexpected NetMessageType: " + tp);
return;
}
try
{
if (tp >= NetMessageType.LibraryError)
{
if (sender != null)
sender.ReceivedLibraryMessage(tp, ptr, payloadByteLength);
else
ReceivedUnconnectedLibraryMessage(now, 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_receiveTime = now;
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 (tp == NetMessageType.Unconnected)
{
// 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);
}
}
else
{
// at this point we know the message type is enabled
// unconnected application (non-library) message
msg.m_incomingMessageType = NetIncomingMessageType.UnconnectedData;
ReleaseMessage(msg);
}
}
resp = resp.Substring(resp.ToLower().IndexOf("location:") + 9);
resp = resp.Substring(0, resp.IndexOf("\r")).Trim();
m_upnp.ExtractServiceUrl(resp);
return;
}
catch (Exception ex)
{
LogError("Packet parsing error: " + ex.Message + " from " + ipsender);
LogDebug("Failed to parse UPnP response: " + ex.ToString());
// don't try to parse this packet further
return;
}
ptr += payloadByteLength;
}
}
NetConnection sender = null;
m_connectionLookup.TryGetValue(ipsender, out sender);
//
// parse packet into messages
//
int numMessages = 0;
int numFragments = 0;
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
numMessages++;
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));
if (isFragment)
numFragments++;
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;
}
m_statistics.PacketReceived(bytesReceived, numMessages, numFragments);
if (sender != null)
sender.m_statistics.PacketReceived(bytesReceived, numMessages, numFragments);
if (tp >= NetMessageType.Unused1 && tp <= NetMessageType.Unused29)
{
ThrowOrLog("Unexpected NetMessageType: " + tp);
return;
}
} while (m_socket.Available > 0);
}
try
{
if (tp >= NetMessageType.LibraryError)
{
if (sender != null)
sender.ReceivedLibraryMessage(tp, ptr, payloadByteLength);
else
ReceivedUnconnectedLibraryMessage(now, ipsender, tp, ptr, payloadByteLength);
}
else
{
if (sender == null && !m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.UnconnectedData))
return; // dropping unconnected message since it's not enabled
/// <summary>
NetIncomingMessage msg = CreateIncomingMessage(NetIncomingMessageType.Data, payloadByteLength);
msg.m_isFragment = isFragment;
msg.m_receiveTime = now;
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 (tp == NetMessageType.Unconnected)
{
// 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);
}
}
else
{
// at this point we know the message type is enabled
// unconnected application (non-library) message
msg.m_incomingMessageType = NetIncomingMessageType.UnconnectedData;
ReleaseMessage(msg);
}
}
}
catch (Exception ex)
{
LogError("Packet parsing error: " + ex.Message + " from " + ipsender);
}
ptr += payloadByteLength;
}
m_statistics.PacketReceived(bytesReceived, numMessages, numFragments);
if (sender != null)
sender.m_statistics.PacketReceived(bytesReceived, numMessages, numFragments);
}
/// <summary>
/// If NetPeerConfiguration.AutoFlushSendQueue() is false; you need to call this to send all messages queued using SendMessage()
/// </summary>
public void FlushSendQueue()