Unstable 1.1.14.0
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -132,28 +132,36 @@ namespace Lidgren.Network
|
||||
catch { }
|
||||
}
|
||||
|
||||
//Avoids allocation on mapping to IPv6
|
||||
private IPEndPoint targetCopy = new IPEndPoint(IPAddress.Any, 0);
|
||||
|
||||
internal bool ActuallySendPacket(byte[] data, int numBytes, NetEndPoint target, out bool connectionReset)
|
||||
{
|
||||
connectionReset = false;
|
||||
|
||||
target = target.MapToFamily(m_socket.AddressFamily);
|
||||
|
||||
IPAddress ba = default(IPAddress);
|
||||
IPAddress ba = default(IPAddress);
|
||||
try
|
||||
{
|
||||
ba = NetUtility.GetCachedBroadcastAddress();
|
||||
|
||||
// TODO: refactor this check outta here
|
||||
if (target.Address == ba)
|
||||
{
|
||||
// Some networks do not allow
|
||||
// a global broadcast so we use the BroadcastAddress from the configuration
|
||||
// this can be resolved to a local broadcast addresss e.g 192.168.x.255
|
||||
target.Address = m_configuration.BroadcastAddress;
|
||||
m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
|
||||
}
|
||||
// TODO: refactor this check outta here
|
||||
if (target.Address.Equals(ba))
|
||||
{
|
||||
// Some networks do not allow
|
||||
// a global broadcast so we use the BroadcastAddress from the configuration
|
||||
// this can be resolved to a local broadcast addresss e.g 192.168.x.255
|
||||
targetCopy.Address = m_configuration.BroadcastAddress;
|
||||
targetCopy.Port = target.Port;
|
||||
m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
|
||||
}
|
||||
else if(m_configuration.DualStack && m_configuration.LocalAddress.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
NetUtility.CopyEndpoint(target, targetCopy); //Maps to IPv6 for Dual Mode
|
||||
else
|
||||
{
|
||||
targetCopy.Port = target.Port;
|
||||
targetCopy.Address = target.Address;
|
||||
}
|
||||
|
||||
int bytesSent = m_socket.SendTo(data, 0, numBytes, SocketFlags.None, target);
|
||||
int bytesSent = m_socket.SendTo(data, 0, numBytes, SocketFlags.None, targetCopy);
|
||||
if (numBytes != bytesSent)
|
||||
LogWarning("Failed to send the full " + numBytes + "; only " + bytesSent + " bytes sent in packet!");
|
||||
|
||||
@@ -181,7 +189,7 @@ namespace Lidgren.Network
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (target.Address == ba)
|
||||
if (target.Address.Equals(ba))
|
||||
m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, false);
|
||||
}
|
||||
return true;
|
||||
@@ -311,4 +319,4 @@ namespace Lidgren.Network
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using System.Threading;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
|
||||
using System.Net.Sockets;
|
||||
#if !__NOIPENDPOINT__
|
||||
using NetEndPoint = System.Net.IPEndPoint;
|
||||
#endif
|
||||
@@ -121,9 +121,16 @@ namespace Lidgren.Network
|
||||
m_connections = new List<NetConnection>();
|
||||
m_connectionLookup = new Dictionary<NetEndPoint, NetConnection>();
|
||||
m_handshakes = new Dictionary<NetEndPoint, NetConnection>();
|
||||
m_senderRemote = (EndPoint)new NetEndPoint(IPAddress.IPv6Any, 0);
|
||||
m_status = NetPeerStatus.NotRunning;
|
||||
m_receivedFragmentGroups = new Dictionary<NetConnection, Dictionary<int, ReceivedFragmentGroup>>();
|
||||
if (m_configuration.LocalAddress.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
{
|
||||
m_senderRemote = (EndPoint)new IPEndPoint(IPAddress.IPv6Any, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_senderRemote = (EndPoint)new IPEndPoint(IPAddress.Any, 0);
|
||||
}
|
||||
m_status = NetPeerStatus.NotRunning;
|
||||
m_receivedFragmentGroups = new Dictionary<NetConnection, Dictionary<int, ReceivedFragmentGroup>>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -292,10 +299,10 @@ namespace Lidgren.Network
|
||||
{
|
||||
if (remoteEndPoint == null)
|
||||
throw new ArgumentNullException("remoteEndPoint");
|
||||
if(m_configuration.DualStack)
|
||||
remoteEndPoint = NetUtility.MapToIPv6(remoteEndPoint);
|
||||
|
||||
remoteEndPoint = remoteEndPoint.MapToFamily(m_socket.AddressFamily);
|
||||
|
||||
lock (m_connections)
|
||||
lock (m_connections)
|
||||
{
|
||||
if (m_status == NetPeerStatus.NotRunning)
|
||||
throw new NetException("Must call Start() first");
|
||||
|
||||
@@ -35,12 +35,12 @@ namespace Lidgren.Network
|
||||
// -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"
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Default MTU value in bytes
|
||||
/// </summary>
|
||||
public const int kDefaultMTU = 1408;
|
||||
|
||||
|
||||
private const string c_isLockedMessage = "You may not modify the NetPeerConfiguration after it has been used to initialize a NetPeer";
|
||||
|
||||
private bool m_isLocked;
|
||||
@@ -48,6 +48,8 @@ namespace Lidgren.Network
|
||||
private string m_networkThreadName;
|
||||
private IPAddress m_localAddress;
|
||||
private IPAddress m_broadcastAddress;
|
||||
private bool m_dualStack;
|
||||
|
||||
internal bool m_acceptIncomingConnections;
|
||||
internal int m_maximumConnections;
|
||||
internal int m_defaultOutgoingMessageCapacity;
|
||||
@@ -93,8 +95,8 @@ namespace Lidgren.Network
|
||||
//
|
||||
m_disabledTypes = NetIncomingMessageType.ConnectionApproval | NetIncomingMessageType.UnconnectedData | NetIncomingMessageType.VerboseDebugMessage | NetIncomingMessageType.ConnectionLatencyUpdated | NetIncomingMessageType.NatIntroductionSuccess;
|
||||
m_networkThreadName = "Lidgren network thread";
|
||||
m_localAddress = IPAddress.IPv6Any;
|
||||
m_broadcastAddress = IPAddress.Broadcast;
|
||||
m_localAddress = IPAddress.Any;
|
||||
m_broadcastAddress = IPAddress.Broadcast;
|
||||
var ip = NetUtility.GetBroadcastAddress();
|
||||
if (ip != null)
|
||||
{
|
||||
@@ -142,12 +144,6 @@ namespace Lidgren.Network
|
||||
get { return m_appIdentifier; }
|
||||
}
|
||||
|
||||
public bool UseDualModeSockets
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = true;
|
||||
|
||||
/// <summary>
|
||||
/// Enables receiving of the specified type of message
|
||||
/// </summary>
|
||||
@@ -332,10 +328,11 @@ namespace Lidgren.Network
|
||||
m_suppressUnreliableUnorderedAcks = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets the local ip address to bind to. Defaults to <see cref="IPAddress.IPv6Any"/>. Cannot be changed once NetPeer is initialized.
|
||||
/// </summary>
|
||||
public IPAddress LocalAddress
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the local ip address to bind to. Defaults to IPAddress.Any. Cannot be changed once NetPeer is initialized.
|
||||
/// </summary>
|
||||
public IPAddress LocalAddress
|
||||
{
|
||||
get { return m_localAddress; }
|
||||
set
|
||||
@@ -346,10 +343,30 @@ namespace Lidgren.Network
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the local broadcast address to use when broadcasting
|
||||
/// </summary>
|
||||
public IPAddress BroadcastAddress
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the library should use IPv6 dual stack mode.
|
||||
/// If you enable this you should make sure that the <see cref="LocalAddress"/> is an IPv6 address.
|
||||
/// Cannot be changed once NetPeer is initialized.
|
||||
/// </summary>
|
||||
public bool DualStack
|
||||
{
|
||||
get { return m_dualStack; }
|
||||
set
|
||||
{
|
||||
if (m_isLocked)
|
||||
throw new NetException(c_isLockedMessage);
|
||||
m_dualStack = value;
|
||||
if (m_dualStack && m_localAddress.Equals(IPAddress.Any))
|
||||
m_localAddress = IPAddress.IPv6Any;
|
||||
if (!m_dualStack && m_localAddress.Equals(IPAddress.IPv6Any))
|
||||
m_localAddress = IPAddress.Any;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the local broadcast address to use when broadcasting
|
||||
/// </summary>
|
||||
public IPAddress BroadcastAddress
|
||||
{
|
||||
get { return m_broadcastAddress; }
|
||||
set
|
||||
|
||||
@@ -98,8 +98,8 @@ namespace Lidgren.Network
|
||||
NetAddress ipAddress = null;
|
||||
if (NetAddress.TryParse(ipOrHost, out ipAddress))
|
||||
{
|
||||
if (ipAddress.AddressFamily == AddressFamily.InterNetwork || ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
{
|
||||
if (ipAddress.AddressFamily == AddressFamily.InterNetwork || ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
{
|
||||
callback(ipAddress);
|
||||
return;
|
||||
}
|
||||
@@ -163,7 +163,7 @@ namespace Lidgren.Network
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Get IPv4 address from notation (xxx.xxx.xxx.xxx) or hostname
|
||||
/// </summary>
|
||||
public static NetAddress Resolve(string ipOrHost)
|
||||
@@ -176,22 +176,22 @@ namespace Lidgren.Network
|
||||
NetAddress ipAddress = null;
|
||||
if (NetAddress.TryParse(ipOrHost, out ipAddress))
|
||||
{
|
||||
if (ipAddress.AddressFamily == AddressFamily.InterNetwork || ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
return ipAddress;
|
||||
throw new ArgumentException("This method will not currently resolve other than IPv4 or IPv6 addresses");
|
||||
}
|
||||
if (ipAddress.AddressFamily == AddressFamily.InterNetwork || ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
return ipAddress;
|
||||
throw new ArgumentException("This method will not currently resolve other than IPv4 or IPv6 addresses");
|
||||
}
|
||||
|
||||
// ok must be a host name
|
||||
try
|
||||
// ok must be a host name
|
||||
try
|
||||
{
|
||||
var addresses = Dns.GetHostAddresses(ipOrHost);
|
||||
if (addresses == null)
|
||||
return null;
|
||||
foreach (var address in addresses)
|
||||
{
|
||||
if (address.AddressFamily == AddressFamily.InterNetwork || address.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
return address;
|
||||
}
|
||||
if (address.AddressFamily == AddressFamily.InterNetwork || address.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
return address;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
catch (SocketException ex)
|
||||
@@ -240,7 +240,7 @@ namespace Lidgren.Network
|
||||
}
|
||||
return new string(c);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the endpoint supplied is on the same subnet as this host
|
||||
/// </summary>
|
||||
@@ -282,6 +282,18 @@ namespace Lidgren.Network
|
||||
return bits;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns how many bits are necessary to hold a certain number
|
||||
/// </summary>
|
||||
[CLSCompliant(false)]
|
||||
public static int BitsToHoldUInt64(ulong value)
|
||||
{
|
||||
int bits = 1;
|
||||
while ((value >>= 1) != 0)
|
||||
bits++;
|
||||
return bits;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns how many bytes are required to hold a certain number of bits
|
||||
/// </summary>
|
||||
@@ -401,7 +413,7 @@ namespace Lidgren.Network
|
||||
{
|
||||
if (j >= h)
|
||||
{
|
||||
if (string.Compare(list[j - h].Name, tmp.Name, StringComparison.OrdinalIgnoreCase) > 0)
|
||||
if (string.Compare(list[j - h].Name, tmp.Name, StringComparison.InvariantCulture) > 0)
|
||||
{
|
||||
list[j] = list[j - h];
|
||||
j -= h;
|
||||
@@ -454,24 +466,28 @@ namespace Lidgren.Network
|
||||
return ComputeSHAHash(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
internal static IPAddress MapToFamily(this IPAddress address, AddressFamily family)
|
||||
{
|
||||
switch (family)
|
||||
{
|
||||
case AddressFamily.InterNetworkV6:
|
||||
return address.MapToIPv6();
|
||||
case AddressFamily.InterNetwork:
|
||||
return address.MapToIPv4();
|
||||
default:
|
||||
throw new Exception($"Unsupported address family: {family}");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies from <paramref name="src"/> to <paramref name="dst"/>. Maps to an IPv6 address
|
||||
/// </summary>
|
||||
/// <param name="src">Source.</param>
|
||||
/// <param name="dst">Destination.</param>
|
||||
internal static void CopyEndpoint(IPEndPoint src, IPEndPoint dst)
|
||||
{
|
||||
dst.Port = src.Port;
|
||||
if (src.AddressFamily == AddressFamily.InterNetwork)
|
||||
dst.Address = src.Address.MapToIPv6();
|
||||
else
|
||||
dst.Address = src.Address;
|
||||
}
|
||||
|
||||
internal static IPEndPoint MapToFamily(this IPEndPoint endpoint, AddressFamily family)
|
||||
{
|
||||
return endpoint.Address.AddressFamily == family
|
||||
? endpoint
|
||||
: new IPEndPoint(endpoint.Address.MapToFamily(family), endpoint.Port);
|
||||
}
|
||||
/// <summary>
|
||||
/// Maps the IPEndPoint object to an IPv6 address. Has allocation
|
||||
/// </summary>
|
||||
internal static IPEndPoint MapToIPv6(IPEndPoint endPoint)
|
||||
{
|
||||
if (endPoint.AddressFamily == AddressFamily.InterNetwork)
|
||||
return new IPEndPoint(endPoint.Address.MapToIPv6(), endPoint.Port);
|
||||
return endPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user