Skip to content

Commit

Permalink
Added option to disable UPnP port forwarding (#1547)
Browse files Browse the repository at this point in the history
* Added option to disable UPnP port forwarding
  • Loading branch information
Measurity authored Jul 26, 2021
1 parent d3670ea commit abbecfe
Show file tree
Hide file tree
Showing 19 changed files with 215 additions and 72 deletions.
39 changes: 39 additions & 0 deletions NitroxModel/DataStructures/AtomicBool.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.Threading;

namespace NitroxModel.DataStructures
{
public sealed class AtomicBool
{
private int backingValue;

public bool Value
{
get => Interlocked.CompareExchange(ref backingValue, 1, 1) == 1;
set
{
if (value)
{
Interlocked.CompareExchange(ref backingValue, 1, 0);
}
else
{
Interlocked.CompareExchange(ref backingValue, 0, 1);
}
}
}

public static implicit operator bool(AtomicBool b)
{
return b.Value;
}

/// <summary>
/// Sets the bool to true if it's false.
/// </summary>
/// <returns>Returns true if the bool was just set to true and wasn't already true.</returns>
public bool GetAndSet()
{
return Interlocked.CompareExchange(ref backingValue, 1, 0) == 0;
}
}
}
1 change: 1 addition & 0 deletions NitroxModel/NitroxModel.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
<Compile Include="Core\IAutoFacRegistrar.cs" />
<Compile Include="Core\NitroxEnvironment.cs" />
<Compile Include="Core\NitroxServiceLocator.cs" />
<Compile Include="DataStructures\AtomicBool.cs" />
<Compile Include="DataStructures\GameLogic\PlantableItemData.cs" />
<Compile Include="DataStructures\GameLogic\DamageTakenData.cs" />
<Compile Include="DataStructures\GameLogic\Entities\Metadata\PrecursorDoorwayMetadata.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using NitroxModel.Networking;
using NitroxModel.Packets;

namespace NitroxServer.Communication.NetworkingLayer.LiteNetLib
namespace NitroxServer.Communication.LiteNetLib
{
public class LiteNetLibConnection : NitroxConnection
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,21 @@
using NitroxServer.GameLogic.Entities;
using NitroxServer.Serialization;

namespace NitroxServer.Communication.NetworkingLayer.LiteNetLib
namespace NitroxServer.Communication.LiteNetLib
{
public class LiteNetLibServer : NitroxServer
{
private readonly NetManager server;
private readonly EventBasedNetListener listener;
private readonly NetPacketProcessor netPacketProcessor = new();
private readonly NetManager server;

public LiteNetLibServer(PacketHandler packetHandler, PlayerManager playerManager, EntitySimulation entitySimulation, ServerConfig serverConfig) : base(packetHandler, playerManager, entitySimulation, serverConfig)
{
netPacketProcessor.SubscribeReusable<WrapperPacket, NetPeer>(OnPacketReceived);
listener = new EventBasedNetListener();
server = new NetManager(listener);
}

public override bool Start()
{
listener.PeerConnectedEvent += PeerConnected;
Expand All @@ -32,25 +33,41 @@ public override bool Start()
server.UpdateTime = 15;
server.UnsyncedEvents = true;
#if DEBUG
server.DisconnectTimeout = 300000; //Disables Timeout (for 5 min) for debug purpose (like if you jump though the server code)
server.DisconnectTimeout = 300000; //Disables Timeout (for 5 min) for debug purpose (like if you jump though the server code)
#endif

if (!server.Start(portNumber))
{
return false;
}

SetupUPNP();

isStopped = false;

#if RELEASE
if (useUpnpPortForwarding)
{
BeginPortForward(portNumber);
}
#endif

return true;
}

public override void Stop()
{
isStopped = true;
server.Stop();
}

public void OnConnectionRequest(ConnectionRequest request)
{
if (server.PeersCount < maxConnections)
{
request.AcceptIfKey("nitrox");
}
else
{
request.Reject();
}
}

private void PeerConnected(NetPeer peer)
{
LiteNetLibConnection connection = new(peer);
Expand All @@ -77,18 +94,6 @@ private void OnPacketReceived(WrapperPacket wrapperPacket, NetPeer peer)
ProcessIncomingData(connection, packet);
}

public void OnConnectionRequest(ConnectionRequest request)
{
if (server.PeersCount < maxConn)
{
request.AcceptIfKey("nitrox");
}
else
{
request.Reject();
}
}

private NitroxConnection GetConnection(int remoteIdentifier)
{
NitroxConnection connection;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using NitroxModel.Packets;
using NitroxModel.Packets.Processors.Abstract;

namespace NitroxServer.Communication.NetworkingLayer
namespace NitroxServer.Communication
{
public interface NitroxConnection : IProcessorContext
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using Mono.Nat;
using NitroxModel.DataStructures;
using NitroxModel.Logger;
using NitroxModel.Packets;
Expand All @@ -9,12 +8,13 @@
using NitroxServer.GameLogic.Entities;
using NitroxServer.Serialization;

namespace NitroxServer.Communication.NetworkingLayer
namespace NitroxServer.Communication
{
public abstract class NitroxServer
{
protected bool isStopped = true;
protected int portNumber, maxConn;
protected readonly int portNumber;
protected readonly int maxConnections;
protected readonly bool useUpnpPortForwarding;

protected readonly PacketHandler packetHandler;
protected readonly EntitySimulation entitySimulation;
Expand All @@ -28,7 +28,8 @@ public NitroxServer(PacketHandler packetHandler, PlayerManager playerManager, En
this.entitySimulation = entitySimulation;

portNumber = serverConfig.ServerPort;
maxConn = serverConfig.MaxConnections;
maxConnections = serverConfig.MaxConnections;
useUpnpPortForwarding = serverConfig.AutoPortForward;
}

public abstract bool Start();
Expand Down Expand Up @@ -56,44 +57,30 @@ protected void ClientDisconnected(NitroxConnection connection)
}
}

protected void ProcessIncomingData(NitroxConnection connection, Packet packet)
protected void BeginPortForward(int port)
{
try
{
packetHandler.Process(packet, connection);
}
catch (Exception ex)
PortForward.TryOpenPortAsync(port, TimeSpan.FromSeconds(20)).ContinueWith(task =>
{
Log.Error(ex, $"Exception while processing packet: {packet}");
}
}

protected void SetupUPNP()
{
NatUtility.DeviceFound += DeviceFound;
NatUtility.StartDiscovery();
if (task.Result)
{
Log.Info($"Server port {port} UDP has been automatically opened on your router (expires in 1 day)");
}
else
{
Log.Warn(PortForward.GetError(port) ?? $"Failed to port forward {port} UDP through UPnP");
}
}).ConfigureAwait(false);
}

private async void DeviceFound(object sender, DeviceEventArgs args)
protected void ProcessIncomingData(NitroxConnection connection, Packet packet)
{
try
{
INatDevice device = args.Device;
await device.CreatePortMapAsync(new Mapping(Protocol.Udp, portNumber, portNumber, (int)TimeSpan.FromDays(1).TotalSeconds, "Nitrox Server - Subnautica"));
Log.Info($"Server port ({portNumber}) has been automatically opened on your router");
packetHandler.Process(packet, connection);
}
catch (MappingException ex)
catch (Exception ex)
{
switch (ex.ErrorCode)
{
case ErrorCode.ConflictInMappingEntry:
Log.Warn($"Automatic port forwarding failed (Is it already open ?)");
break;
default:
Log.Warn($"Automatic port forwarding failed, please manually port forward");
break;

}
Log.Error(ex, $"Exception while processing packet: {packet}");
}
}
}
Expand Down
1 change: 0 additions & 1 deletion NitroxServer/Communication/Packets/PacketHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using NitroxServer.GameLogic;
using NitroxModel.Core;
using NitroxModel.DataStructures.Util;
using NitroxServer.Communication.NetworkingLayer;

namespace NitroxServer.Communication.Packets
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using NitroxModel.Packets;
using NitroxModel.Packets.Processors.Abstract;
using NitroxServer.Communication.NetworkingLayer;

namespace NitroxServer.Communication.Packets.Processors.Abstract
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using NitroxModel.Logger;
using NitroxModel.Packets;
using NitroxModel.Server;
using NitroxServer.Communication.NetworkingLayer;
using NitroxServer.Communication.Packets.Processors.Abstract;
using NitroxServer.Serialization;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using NitroxModel.Logger;
using NitroxModel.MultiplayerSession;
using NitroxModel.Packets;
using NitroxServer.Communication.NetworkingLayer;
using NitroxServer.Communication.Packets.Processors.Abstract;
using NitroxServer.GameLogic;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using NitroxModel.DataStructures.GameLogic;
using NitroxModel.DataStructures.Util;
using NitroxModel.Packets;
using NitroxServer.Communication.NetworkingLayer;
using NitroxServer.Communication.Packets.Processors.Abstract;
using NitroxServer.GameLogic;
using NitroxServer.Serialization.World;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using NitroxServer.GameLogic;
using NitroxServer.GameLogic.Unlockables;

namespace NitroxServer
namespace NitroxServer.Communication.Packets.Processors
{
public class RadioPlayPendingMessageProcessor : AuthenticatedPacketProcessor<RadioPlayPendingMessage>
{
Expand Down
Loading

0 comments on commit abbecfe

Please sign in to comment.