Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions TorrentCore.Cli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@ public static void Main(string[] args)
string input = null;
string output = null;
bool verbose = false;
bool upnp = false;
ArgumentSyntax.Parse(args, syntax =>
{
syntax.DefineOption("p|port", ref port, "Port to listen for incoming connections on.");
syntax.DefineOption("o|output", ref output, "Path to save downloaded files to.");
syntax.DefineOption("v|verbose", ref verbose, "Show detailed logging information.");
syntax.DefineOption("u|upnp", ref upnp, "Use UPnP for port forwarding.");
var uiPortArgument = syntax.DefineOption("ui", ref uiPort, false, "Run a web UI, optionally specifying the port to listen on (default: 5001).");
runWebUi = uiPortArgument.IsSpecified;

Expand All @@ -53,6 +55,10 @@ public static void Main(string[] args)
// Listen for incoming connections on the specified port
builder.UsePort(port);

// If upnp is selected use it.
if (upnp)
builder.AddUPnP();

// Add extension protocol
builder.ConfigureServices(services =>
{
Expand Down
4 changes: 4 additions & 0 deletions TorrentCore.Cli/TorrentCore.Cli.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
<DocumentationFile>bin\Debug\$(AssemblyName).xml</DocumentationFile>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
Comment on lines +15 to +17
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks unnecessary, can you remove it?


<ItemGroup>
<AdditionalFiles Include="..\stylecop.json" Visible="false" />
</ItemGroup>
Expand Down
10 changes: 10 additions & 0 deletions TorrentCore/TorrentClientBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,16 @@ public TorrentClientBuilder UsePort(int port)
return this;
}

/// <summary>
/// Add UPnP port forwarding feature.
/// </summary>
/// <returns>TorrentClientBuilder.</returns>
public TorrentClientBuilder AddUPnP()
{
_services.Configure<LocalTcpConnectionOptions>(options => options.UseUPnP = true);
return this;
}

/// <summary>
/// Sets up a default Torrent Client using the TCP transport protocol and the BitTorrent application protocol.
/// </summary>
Expand Down
6 changes: 6 additions & 0 deletions TorrentCore/TorrentClientSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,19 @@ public TorrentClientSettings()
PeerId = PeerId.CreateNew();
ListenPort = 6881;
AdapterAddress = IPAddress.Any;
UseUPnP = false;
}

/// <summary>
/// Gets or sets the Peer ID for the local client.
/// </summary>
public PeerId PeerId { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to use UPnP for port forwarding.
/// </summary>
public bool UseUPnP { get; set; }

/// <summary>
/// Gets or sets the port to listen for incoming connections on.
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions TorrentCore/TorrentCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.2.0" />
<PackageReference Include="Open.NAT.Core" Version="2.1.0" />
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This library looks to be based on Mono.Nat which seems to have more usage. Would it be better to use the Mono library instead of this fork?

<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
<PackageReference Include="System.Net.Sockets" Version="4.3.0" />
Expand Down
16 changes: 16 additions & 0 deletions TorrentCore/Transport/IUPnPClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// This file is part of TorrentCore.
// https://torrentcore.org
// Copyright (c) Samuel Fisher.
//
// Licensed under the GNU Lesser General Public License, version 3. See the
// LICENSE file in the project root for full license information.

using System.Threading.Tasks;

namespace TorrentCore.Transport
{
public interface IUPnPClient
{
Task TryAddPortMappingAsync(int port);
}
}
5 changes: 5 additions & 0 deletions TorrentCore/Transport/Tcp/LocalTcpConnectionOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,10 @@ public class LocalTcpConnectionOptions
/// Gets or sets the address of the local adapter used for connections.
/// </summary>
public IPAddress BindAddress { get; set; } = IPAddress.Any;

/// <summary>
/// Gets or sets a value indicating whether to use UPnP for port forwarding.
/// </summary>
public bool UseUPnP { get; set; }
}
}
4 changes: 4 additions & 0 deletions TorrentCore/Transport/Tcp/TcpTransportProtocol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class TcpTransportProtocol : ITcpTransportProtocol
{
private readonly ILogger<TcpTransportProtocol> _logger;
private readonly ConcurrentBag<TcpTransportStream> _streams;
private readonly IUPnPClient _uPnPClient;

private TcpListener _listener;

Expand All @@ -40,6 +41,7 @@ public TcpTransportProtocol(ILogger<TcpTransportProtocol> logger, IOptions<Local
_logger = logger;
_streams = new ConcurrentBag<TcpTransportStream>();
Port = options.Value.Port;
_uPnPClient = new TcpTransportUPnPClient(options.Value.UseUPnP);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you register this in the DI container and inject it instead of creating it here? This will allow users more flexibility to change how UPnP is handled if required.

LocalBindAddress = options.Value.BindAddress ?? IPAddress.Any;
RateLimiter = new RateLimiter();
}
Expand Down Expand Up @@ -108,6 +110,8 @@ public void Start()
// If port=0 was supplied, set the actual port we are listening on.
Port = ((IPEndPoint)_listener.LocalEndpoint).Port;
ListenForIncomingConnections();

_uPnPClient.TryAddPortMappingAsync(Port);
}

/// <summary>
Expand Down
42 changes: 42 additions & 0 deletions TorrentCore/Transport/Tcp/TcpTransportUPnPClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// This file is part of TorrentCore.
// https://torrentcore.org
// Copyright (c) Samuel Fisher.
//
// Licensed under the GNU Lesser General Public License, version 3. See the
// LICENSE file in the project root for full license information.

using System.Threading;
using System.Threading.Tasks;
using Open.Nat;

namespace TorrentCore.Transport.Tcp
{
class TcpTransportUPnPClient : IUPnPClient
{
private bool _useUPnP;

public TcpTransportUPnPClient(bool useUPnP)
{
_useUPnP = useUPnP;
}

public async Task TryAddPortMappingAsync(int port)
{
if (!_useUPnP)
return;

try
{
var discoverer = new NatDiscoverer();
var cts = new CancellationTokenSource(10000);

var device = await discoverer.DiscoverDeviceAsync(PortMapper.Upnp, cts);
await device.CreatePortMapAsync(new Mapping(Protocol.Tcp, port, port, "TorrentCore"));
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't take into consideration which IP the application is listening on (TorrentClientSettings.AdapterAddress).

For context, AdapterAddress is used for situations such as forcing TorrentCore to run over a VPN connection. In this situation it could end up adding the mapping onto a network the user specifically doesn't want TorrentCore to be using.

}
catch
{
// Do nothing
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What type of exceptions does this throw? It could do with some logging to indicate something has gone wrong.

}
}
}
}