2023-05-29 22:23:11 +02:00
/ * 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.Net ;
namespace Lidgren.Network
{
/// <summary>
/// Partly immutable after NetPeer has been initialized
/// </summary>
public sealed class NetPeerConfiguration
{
// 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"
2024-01-01 21:23:01 +01:00
2023-05-29 22:23:11 +02:00
/// <summary>
/// Default MTU value in bytes
/// </summary>
public const int kDefaultMTU = 1408 ;
2024-01-01 21:23:01 +01:00
2023-05-29 22:23:11 +02:00
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 ;
private IPAddress m_broadcastAddress ;
2024-01-01 21:23:01 +01:00
private bool m_dualStack ;
2023-05-29 22:23:11 +02:00
internal bool m_acceptIncomingConnections ;
internal int m_maximumConnections ;
internal int m_defaultOutgoingMessageCapacity ;
internal float m_pingInterval ;
internal bool m_useMessageRecycling ;
internal int m_recycledCacheMaxCount ;
internal float m_connectionTimeout ;
internal bool m_enableUPnP ;
internal bool m_autoFlushSendQueue ;
private NetUnreliableSizeBehaviour m_unreliableSizeBehaviour ;
internal bool m_suppressUnreliableUnorderedAcks ;
internal NetIncomingMessageType m_disabledTypes ;
internal int m_port ;
internal int m_receiveBufferSize ;
internal int m_sendBufferSize ;
internal float m_resendHandshakeInterval ;
internal int m_maximumHandshakeAttempts ;
// bad network simulation
internal float m_loss ;
internal float m_duplicates ;
internal float m_minimumOneWayLatency ;
internal float m_randomOneWayLatency ;
// MTU
internal int m_maximumTransmissionUnit ;
internal bool m_autoExpandMTU ;
internal float m_expandMTUFrequency ;
internal int m_expandMTUFailAttempts ;
/// <summary>
/// NetPeerConfiguration constructor
/// </summary>
public NetPeerConfiguration ( string appIdentifier )
{
if ( string . IsNullOrEmpty ( appIdentifier ) )
throw new NetException ( "App identifier must be at least one character long" ) ;
m_appIdentifier = appIdentifier ;
//
// default values
//
m_disabledTypes = NetIncomingMessageType . ConnectionApproval | NetIncomingMessageType . UnconnectedData | NetIncomingMessageType . VerboseDebugMessage | NetIncomingMessageType . ConnectionLatencyUpdated | NetIncomingMessageType . NatIntroductionSuccess ;
m_networkThreadName = "Lidgren network thread" ;
m_localAddress = IPAddress . Any ;
m_broadcastAddress = IPAddress . Broadcast ;
var ip = NetUtility . GetBroadcastAddress ( ) ;
if ( ip ! = null )
{
m_broadcastAddress = ip ;
}
m_port = 0 ;
m_receiveBufferSize = 131071 ;
m_sendBufferSize = 131071 ;
m_acceptIncomingConnections = false ;
m_maximumConnections = 32 ;
m_defaultOutgoingMessageCapacity = 16 ;
m_pingInterval = 4.0f ;
m_connectionTimeout = 25.0f ;
m_useMessageRecycling = true ;
m_recycledCacheMaxCount = 64 ;
m_resendHandshakeInterval = 3.0f ;
m_maximumHandshakeAttempts = 5 ;
m_autoFlushSendQueue = true ;
m_suppressUnreliableUnorderedAcks = false ;
m_maximumTransmissionUnit = kDefaultMTU ;
m_autoExpandMTU = false ;
m_expandMTUFrequency = 2.0f ;
m_expandMTUFailAttempts = 5 ;
m_unreliableSizeBehaviour = NetUnreliableSizeBehaviour . IgnoreMTU ;
m_loss = 0.0f ;
m_minimumOneWayLatency = 0.0f ;
m_randomOneWayLatency = 0.0f ;
m_duplicates = 0.0f ;
m_isLocked = false ;
}
internal void Lock ( )
{
m_isLocked = true ;
}
/// <summary>
/// Gets the identifier of this application; the library can only connect to matching app identifier peers
/// </summary>
public string AppIdentifier
{
get { return m_appIdentifier ; }
}
/// <summary>
/// Enables receiving of the specified type of message
/// </summary>
public void EnableMessageType ( NetIncomingMessageType type )
{
m_disabledTypes & = ( ~ type ) ;
}
/// <summary>
/// Disables receiving of the specified type of message
/// </summary>
public void DisableMessageType ( NetIncomingMessageType type )
{
m_disabledTypes | = type ;
}
/// <summary>
/// Enables or disables receiving of the specified type of message
/// </summary>
public void SetMessageTypeEnabled ( NetIncomingMessageType type , bool enabled )
{
if ( enabled )
m_disabledTypes & = ( ~ type ) ;
else
m_disabledTypes | = type ;
}
/// <summary>
/// Gets if receiving of the specified type of message is enabled
/// </summary>
public bool IsMessageTypeEnabled ( NetIncomingMessageType type )
{
return ! ( ( m_disabledTypes & type ) = = type ) ;
}
/// <summary>
/// Gets or sets the behaviour of unreliable sends above MTU
/// </summary>
public NetUnreliableSizeBehaviour UnreliableSizeBehaviour
{
get { return m_unreliableSizeBehaviour ; }
set { m_unreliableSizeBehaviour = value ; }
}
/// <summary>
/// Gets or sets the name of the library network thread. Cannot be changed once NetPeer is initialized.
/// </summary>
public string NetworkThreadName
{
get { return m_networkThreadName ; }
set
{
if ( m_isLocked )
throw new NetException ( "NetworkThreadName may not be set after the NetPeer which uses the configuration has been started" ) ;
m_networkThreadName = value ;
}
}
/// <summary>
/// Gets or sets the maximum amount of connections this peer can hold. Cannot be changed once NetPeer is initialized.
/// </summary>
public int MaximumConnections
{
get { return m_maximumConnections ; }
set
{
if ( m_isLocked )
throw new NetException ( c_isLockedMessage ) ;
m_maximumConnections = value ;
}
}
/// <summary>
/// Gets or sets the maximum amount of bytes to send in a single packet, excluding ip, udp and lidgren headers. Cannot be changed once NetPeer is initialized.
/// </summary>
public int MaximumTransmissionUnit
{
get { return m_maximumTransmissionUnit ; }
set
{
if ( m_isLocked )
throw new NetException ( c_isLockedMessage ) ;
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 ;
}
}
/// <summary>
/// Gets or sets the default capacity in bytes when NetPeer.CreateMessage() is called without argument
/// </summary>
public int DefaultOutgoingMessageCapacity
{
get { return m_defaultOutgoingMessageCapacity ; }
set { m_defaultOutgoingMessageCapacity = value ; }
}
/// <summary>
/// Gets or sets the time between latency calculating pings
/// </summary>
public float PingInterval
{
get { return m_pingInterval ; }
set { m_pingInterval = value ; }
}
/// <summary>
/// Gets or sets if the library should recycling messages to avoid excessive garbage collection. Cannot be changed once NetPeer is initialized.
/// </summary>
public bool UseMessageRecycling
{
get { return m_useMessageRecycling ; }
set
{
if ( m_isLocked )
throw new NetException ( c_isLockedMessage ) ;
m_useMessageRecycling = value ;
}
}
/// <summary>
/// Gets or sets the maximum number of incoming/outgoing messages to keep in the recycle cache.
/// </summary>
public int RecycledCacheMaxCount
{
get { return m_recycledCacheMaxCount ; }
set
{
if ( m_isLocked )
throw new NetException ( c_isLockedMessage ) ;
m_recycledCacheMaxCount = value ;
}
}
/// <summary>
/// Gets or sets the number of seconds timeout will be postponed on a successful ping/pong
/// </summary>
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 ;
}
}
/// <summary>
/// Enables UPnP support; enabling port forwarding and getting external ip
/// </summary>
public bool EnableUPnP
{
get { return m_enableUPnP ; }
set
{
if ( m_isLocked )
throw new NetException ( c_isLockedMessage ) ;
m_enableUPnP = value ;
}
}
/// <summary>
/// Enables or disables automatic flushing of the send queue. If disabled, you must manully call NetPeer.FlushSendQueue() to flush sent messages to network.
/// </summary>
public bool AutoFlushSendQueue
{
get { return m_autoFlushSendQueue ; }
set { m_autoFlushSendQueue = value ; }
}
/// <summary>
/// If true, will not send acks for unreliable unordered messages. This will save bandwidth, but disable flow control and duplicate detection for this type of messages.
/// </summary>
public bool SuppressUnreliableUnorderedAcks
{
get { return m_suppressUnreliableUnorderedAcks ; }
set
{
if ( m_isLocked )
throw new NetException ( c_isLockedMessage ) ;
m_suppressUnreliableUnorderedAcks = value ;
}
}
/// <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
{
if ( m_isLocked )
throw new NetException ( c_isLockedMessage ) ;
m_localAddress = value ;
}
}
2024-01-01 21:23:01 +01:00
/// <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 ;
}
}
/// <summary>
/// Gets or sets the local broadcast address to use when broadcasting
/// </summary>
public IPAddress BroadcastAddress
2023-05-29 22:23:11 +02:00
{
get { return m_broadcastAddress ; }
set
{
if ( m_isLocked )
throw new NetException ( c_isLockedMessage ) ;
m_broadcastAddress = value ;
}
}
/// <summary>
/// Gets or sets the local port to bind to. Defaults to 0. Cannot be changed once NetPeer is initialized.
/// </summary>
public int Port
{
get { return m_port ; }
set
{
if ( m_isLocked )
throw new NetException ( c_isLockedMessage ) ;
m_port = value ;
}
}
/// <summary>
/// Gets or sets the size in bytes of the receiving buffer. Defaults to 131071 bytes. Cannot be changed once NetPeer is initialized.
/// </summary>
public int ReceiveBufferSize
{
get { return m_receiveBufferSize ; }
set
{
if ( m_isLocked )
throw new NetException ( c_isLockedMessage ) ;
m_receiveBufferSize = value ;
}
}
/// <summary>
/// Gets or sets the size in bytes of the sending buffer. Defaults to 131071 bytes. Cannot be changed once NetPeer is initialized.
/// </summary>
public int SendBufferSize
{
get { return m_sendBufferSize ; }
set
{
if ( m_isLocked )
throw new NetException ( c_isLockedMessage ) ;
m_sendBufferSize = value ;
}
}
/// <summary>
/// Gets or sets if the NetPeer should accept incoming connections. This is automatically set to true in NetServer and false in NetClient.
/// </summary>
public bool AcceptIncomingConnections
{
get { return m_acceptIncomingConnections ; }
set { m_acceptIncomingConnections = value ; }
}
/// <summary>
/// Gets or sets the number of seconds between handshake attempts
/// </summary>
public float ResendHandshakeInterval
{
get { return m_resendHandshakeInterval ; }
set { m_resendHandshakeInterval = value ; }
}
/// <summary>
/// Gets or sets the maximum number of handshake attempts before failing to connect
/// </summary>
public int MaximumHandshakeAttempts
{
get { return m_maximumHandshakeAttempts ; }
set
{
if ( value < 1 )
throw new NetException ( "MaximumHandshakeAttempts must be at least 1" ) ;
m_maximumHandshakeAttempts = value ;
}
}
/// <summary>
/// Gets or sets if the NetPeer should send large messages to try to expand the maximum transmission unit size
/// </summary>
public bool AutoExpandMTU
{
get { return m_autoExpandMTU ; }
set
{
if ( m_isLocked )
throw new NetException ( c_isLockedMessage ) ;
m_autoExpandMTU = value ;
}
}
/// <summary>
/// Gets or sets how often to send large messages to expand MTU if AutoExpandMTU is enabled
/// </summary>
public float ExpandMTUFrequency
{
get { return m_expandMTUFrequency ; }
set { m_expandMTUFrequency = value ; }
}
/// <summary>
/// Gets or sets the number of failed expand mtu attempts to perform before setting final MTU
/// </summary>
public int ExpandMTUFailAttempts
{
get { return m_expandMTUFailAttempts ; }
set { m_expandMTUFailAttempts = value ; }
}
#if DEBUG
/// <summary>
/// Gets or sets the simulated amount of sent packets lost from 0.0f to 1.0f
/// </summary>
public float SimulatedLoss
{
get { return m_loss ; }
set { m_loss = value ; }
}
/// <summary>
/// Gets or sets the minimum simulated amount of one way latency for sent packets in seconds
/// </summary>
public float SimulatedMinimumLatency
{
get { return m_minimumOneWayLatency ; }
set { m_minimumOneWayLatency = value ; }
}
/// <summary>
/// Gets or sets the simulated added random amount of one way latency for sent packets in seconds
/// </summary>
public float SimulatedRandomLatency
{
get { return m_randomOneWayLatency ; }
set { m_randomOneWayLatency = value ; }
}
/// <summary>
/// Gets the average simulated one way latency in seconds
/// </summary>
public float SimulatedAverageLatency
{
get { return m_minimumOneWayLatency + ( m_randomOneWayLatency * 0.5f ) ; }
}
/// <summary>
/// Gets or sets the simulated amount of duplicated packets from 0.0f to 1.0f
/// </summary>
public float SimulatedDuplicatesChance
{
get { return m_duplicates ; }
set { m_duplicates = value ; }
}
#endif
/// <summary>
/// Creates a memberwise shallow clone of this configuration
/// </summary>
public NetPeerConfiguration Clone ( )
{
NetPeerConfiguration retval = this . MemberwiseClone ( ) as NetPeerConfiguration ;
retval . m_isLocked = false ;
return retval ;
}
}
/// <summary>
/// Behaviour of unreliable sends above MTU
/// </summary>
public enum NetUnreliableSizeBehaviour
{
/// <summary>
/// Sending an unreliable message will ignore MTU and send everything in a single packet; this is the new default
/// </summary>
IgnoreMTU = 0 ,
/// <summary>
/// Old behaviour; use normal fragmentation for unreliable messages - if a fragment is dropped, memory for received fragments are never reclaimed!
/// </summary>
NormalFragmentation = 1 ,
/// <summary>
/// Alternate behaviour; just drops unreliable messages above MTU
/// </summary>
DropAboveMTU = 2 ,
}
}