Skip to content

Commit

Permalink
[webseed] Make some timeouts configurable
Browse files Browse the repository at this point in the history
Increase some timeouts as some web servers, specifically some
from internet archive, take longer than 10 seconds to respond,
which means the time between block requests can be significantly
longer than 15 seconds too.

These new (arbitrary) values are enough to reliably download from
both webseed urls for the public domain torrent listed in

#538
  • Loading branch information
alanmcgovern committed Jun 24, 2022
1 parent 052a0e8 commit 35c1c43
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 48 deletions.
7 changes: 3 additions & 4 deletions src/MonoTorrent.Client/MonoTorrent.Client.Modes/Mode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,6 @@ void PostLogicTick (int counter)
{
PeerId id;

var fifteenSeconds = TimeSpan.FromSeconds (15);
var ninetySeconds = TimeSpan.FromSeconds (90);
var onhundredAndEightySeconds = TimeSpan.FromSeconds (180);

Expand All @@ -638,7 +637,7 @@ void PostLogicTick (int counter)
continue;
}

if (id.LastBlockReceived.Elapsed > fifteenSeconds && id.AmRequestingPiecesCount > 0) {
if (id.LastBlockReceived.Elapsed > Settings.StaleRequestTimeout && id.AmRequestingPiecesCount > 0) {
ConnectionManager.CleanupSocket (Manager, id);
i--;
continue;
Expand All @@ -654,13 +653,13 @@ void PostLogicTick (int counter)

void DownloadLogic (int counter)
{
if (ClientEngine.SupportsWebSeed && (DateTime.Now - Manager.StartTime) > Manager.Settings.WebSeedDelay && Manager.Monitor.DownloadRate < Manager.Settings.WebSeedSpeedTrigger) {
if (ClientEngine.SupportsWebSeed && (DateTime.Now - Manager.StartTime) > Settings.WebSeedDelay && Manager.Monitor.DownloadRate < Settings.WebSeedSpeedTrigger) {
foreach (Uri uri in Manager.Torrent!.HttpSeeds) {
BEncodedString peerId = CreatePeerId ();

var peer = new Peer (peerId, uri);

var connection = new HttpPeerConnection (Manager, Manager.Engine!.Factories, uri);
var connection = new HttpPeerConnection (Manager, Settings.WebSeedConnectionTimeout, Manager.Engine!.Factories, uri);
// Unsupported connection type.
if (connection == null)
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,15 @@ public sealed class EngineSettings : IEquatable<EngineSettings>
/// </summary>
public IPEndPoint? ReportedAddress { get; }

/// <summary>
/// When blocks have been requested from a peer, the connection to that peer will be closed and the
/// requests will be cancelled if it takes longer than this time to receive a 16kB block. This
/// value must be higher than <see cref="WebSeedConnectionTimeout"/> or the web seeds will be
/// considered unhealthy before their connection timeout is exceeded.
/// Defaults to 40 seconds.
/// </summary>
public TimeSpan StaleRequestTimeout { get; } = TimeSpan.FromSeconds (40);

/// <summary>
/// This is the full path to a sub-directory of <see cref="CacheDirectory"/>. If a magnet link is used
/// to download a torrent, the downloaded metata will be cached here.
Expand All @@ -210,6 +219,24 @@ public sealed class EngineSettings : IEquatable<EngineSettings>
/// </summary>
public bool UsePartialFiles { get; } = false;

/// <summary>
/// The timeout used when connecting to a WebSeed's HTTP endpoint.
/// Defaults to 30 seconds.
/// </summary>
public TimeSpan WebSeedConnectionTimeout { get; } = TimeSpan.FromSeconds (30);

/// <summary>
/// The delay before a torrent will start using web seeds.
/// Defaults to 1 minute.
/// </summary>
public TimeSpan WebSeedDelay { get; } = TimeSpan.FromMinutes (1);

/// <summary>
/// The download speed under which a torrent will start using web seeds.
/// Defaults to 15kB/sec.
/// </summary>
public int WebSeedSpeedTrigger { get; } = 15 * 1024;

public EngineSettings ()
{

Expand All @@ -220,7 +247,8 @@ internal EngineSettings (
bool autoSaveLoadDhtCache, bool autoSaveLoadFastResume, bool autoSaveLoadMagnetLinkMetadata, string cacheDirectory,
TimeSpan connectionTimeout, IPEndPoint? dhtEndPoint, int diskCacheBytes, FastResumeMode fastResumeMode, IPEndPoint? listenEndPoint,
int maximumConnections, int maximumDiskReadRate, int maximumDiskWriteRate, int maximumDownloadRate, int maximumHalfOpenConnections,
int maximumOpenFiles, int maximumUploadRate, IPEndPoint? reportedAddress, bool usePartialFiles)
int maximumOpenFiles, int maximumUploadRate, IPEndPoint? reportedAddress, bool usePartialFiles,
TimeSpan webSeedConnectionTimeout, TimeSpan webSeedDelay, int webSeedSpeedTrigger, TimeSpan staleRequestTimeout)
{
// Make sure this is immutable now
AllowedEncryption = EncryptionTypes.MakeReadOnly (allowedEncryption);
Expand All @@ -244,7 +272,11 @@ internal EngineSettings (
MaximumOpenFiles = maximumOpenFiles;
MaximumUploadRate = maximumUploadRate;
ReportedAddress = reportedAddress;
StaleRequestTimeout = staleRequestTimeout;
UsePartialFiles = usePartialFiles;
WebSeedConnectionTimeout = webSeedConnectionTimeout;
WebSeedDelay = webSeedDelay;
WebSeedSpeedTrigger = webSeedSpeedTrigger;
}

internal string GetDhtNodeCacheFilePath ()
Expand Down Expand Up @@ -288,7 +320,11 @@ public bool Equals (EngineSettings? other)
&& MaximumOpenFiles == other.MaximumOpenFiles
&& MaximumUploadRate == other.MaximumUploadRate
&& ReportedAddress == other.ReportedAddress
&& StaleRequestTimeout == other.StaleRequestTimeout
&& UsePartialFiles == other.UsePartialFiles
&& WebSeedConnectionTimeout == other.WebSeedConnectionTimeout
&& WebSeedDelay == other.WebSeedDelay
&& WebSeedSpeedTrigger == other.WebSeedSpeedTrigger
;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ internal static EngineSettings CreateForTests (
int maximumHalfOpenConnections;
int maximumOpenFiles;
int maximumUploadRate;
TimeSpan staleRequestTimeout;
TimeSpan webSeedConnectionTimeout;
TimeSpan webSeedDelay;
int webSeedSpeedTrigger;


/// <summary>
/// A prioritised list of encryption methods, including plain text, which can be used to connect to another peer.
Expand Down Expand Up @@ -253,12 +258,49 @@ public int MaximumDiskWriteRate {
/// </summary>
public IPEndPoint? ReportedAddress { get; set; }

/// <summary>
/// When blocks have been requested from a peer, the connection to that peer will be closed and the
/// requests will be cancelled if it takes longer than this time to receive a 16kB block. This
/// value must be higher than <see cref="WebSeedConnectionTimeout"/> or the web seeds will be
/// considered unhealthy before their connection timeout is exceeded. Defaults to 40 seconds.
/// </summary>
public TimeSpan StaleRequestTimeout {
get => staleRequestTimeout;
set => staleRequestTimeout = CheckZeroOrPositive (value);
}

/// <summary>
/// If set to <see langword="true"/> then partially downloaded files will have ".!mt" appended to their filename. When the file is fully downloaded, the ".!mt" suffix will be removed.
/// Defaults to <see langword="false"/> as this is a pre-release feature.
/// </summary>
public bool UsePartialFiles { get; set; }

/// <summary>
/// The timeout used when connecting to a WebSeed's HTTP endpoint.
/// </summary>
public TimeSpan WebSeedConnectionTimeout {
get => webSeedConnectionTimeout;
set => webSeedConnectionTimeout = CheckZeroOrPositive (value);
}

/// <summary>
/// The delay before a torrent will start using web seeds. A value of zero
/// means 'immediately'. Using webseeds by default is not recommended
/// </summary>
public TimeSpan WebSeedDelay {
get => webSeedDelay;
set => webSeedDelay = CheckZeroOrPositive (value);
}

/// <summary>
/// The download speed under which a torrent will start using web seeds. A value of
/// 0 means webseeds will be added regardless of how fast the torrent is downloading.
/// </summary>
public int WebSeedSpeedTrigger {
get => webSeedSpeedTrigger;
set => webSeedSpeedTrigger = CheckZeroOrPositive (value);
}

public EngineSettingsBuilder ()
: this (new EngineSettings ())
{
Expand Down Expand Up @@ -289,7 +331,11 @@ public EngineSettingsBuilder (EngineSettings settings)
MaximumOpenFiles = settings.MaximumOpenFiles;
MaximumUploadRate = settings.MaximumUploadRate;
ReportedAddress = settings.ReportedAddress;
StaleRequestTimeout = settings.StaleRequestTimeout;
UsePartialFiles = settings.UsePartialFiles;
WebSeedConnectionTimeout = settings.WebSeedConnectionTimeout;
WebSeedDelay = settings.WebSeedDelay;
WebSeedSpeedTrigger = settings.WebSeedSpeedTrigger;
}

public EngineSettings ToSettings ()
Expand Down Expand Up @@ -323,7 +369,11 @@ public EngineSettings ToSettings ()
maximumOpenFiles: MaximumOpenFiles,
maximumUploadRate: MaximumUploadRate,
reportedAddress: ReportedAddress,
usePartialFiles: UsePartialFiles
staleRequestTimeout: StaleRequestTimeout,
usePartialFiles: UsePartialFiles,
webSeedConnectionTimeout: WebSeedConnectionTimeout,
webSeedDelay: WebSeedDelay,
webSeedSpeedTrigger: webSeedSpeedTrigger
);
}

Expand All @@ -340,5 +390,12 @@ static int CheckZeroOrPositive (int value)
throw new ArgumentOutOfRangeException (nameof (value), "Value should be zero or greater");
return value;
}

static TimeSpan CheckZeroOrPositive (TimeSpan value)
{
if (value < TimeSpan.Zero)
throw new ArgumentOutOfRangeException ("value", "must be greater than or equal to TimeSpan.Zero");
return value;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,16 +79,6 @@ public sealed class TorrentSettings : IEquatable<TorrentSettings>
/// </summary>
public int UploadSlots { get; } = 8;

/// <summary>
/// The delay before a torrent will start using web seeds.
/// </summary>
public TimeSpan WebSeedDelay { get; } = TimeSpan.FromMinutes (1);

/// <summary>
/// The download speed under which a torrent will start using web seeds.
/// </summary>
public int WebSeedSpeedTrigger { get; } = 15 * 1024;

/// <summary>
/// When considering peers that have given us data, the inactivity manager will wait TimeToWaiTUntilIdle plus (Number of bytes we've been sent / ConnectionRetentionFactor) seconds
/// before they are eligible for disconnection. Default value is 2000. A value of 0 prevents the inactivity manager from disconnecting peers that have sent data.
Expand All @@ -112,7 +102,7 @@ public TorrentSettings ()

}

internal TorrentSettings (bool allowDht, bool allowInitialSeeding, bool allowPeerExchange, int maximumConnections, int maximumDownloadRate, int maximumUploadRate, int uploadSlots, TimeSpan webSeedDelay, int webSeedSpeedTrigger, bool createContainingDirectory)
internal TorrentSettings (bool allowDht, bool allowInitialSeeding, bool allowPeerExchange, int maximumConnections, int maximumDownloadRate, int maximumUploadRate, int uploadSlots, bool createContainingDirectory)
{
AllowDht = allowDht;
AllowInitialSeeding = allowInitialSeeding;
Expand All @@ -122,8 +112,6 @@ internal TorrentSettings (bool allowDht, bool allowInitialSeeding, bool allowPee
MaximumDownloadRate = maximumDownloadRate;
MaximumUploadRate = maximumUploadRate;
UploadSlots = uploadSlots;
WebSeedDelay = webSeedDelay;
WebSeedSpeedTrigger = webSeedSpeedTrigger;
}

public override bool Equals (object? obj)
Expand All @@ -139,9 +127,7 @@ public bool Equals (TorrentSettings? other)
&& MaximumConnections == other.MaximumConnections
&& MaximumDownloadRate == other.MaximumDownloadRate
&& MaximumUploadRate == other.MaximumUploadRate
&& UploadSlots == other.UploadSlots
&& WebSeedDelay == other.WebSeedDelay
&& WebSeedSpeedTrigger == other.WebSeedSpeedTrigger;
&& UploadSlots == other.UploadSlots;
}

public override int GetHashCode ()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,6 @@ public int UploadSlots {
set => uploadSlots = CheckZeroOrPositive (value);
}

/// <summary>
/// The delay before a torrent will start using web seeds.
/// </summary>
public TimeSpan WebSeedDelay { get; set; }

/// <summary>
/// The download speed under which a torrent will start using web seeds.
/// </summary>
public int WebSeedSpeedTrigger { get; set; }

public TorrentSettingsBuilder ()
: this (new TorrentSettings ())
{
Expand All @@ -122,23 +112,19 @@ public TorrentSettingsBuilder (TorrentSettings settings)
MaximumDownloadRate = settings.MaximumDownloadRate;
MaximumUploadRate = settings.MaximumUploadRate;
UploadSlots = settings.UploadSlots;
WebSeedDelay = settings.WebSeedDelay;
WebSeedSpeedTrigger = settings.WebSeedSpeedTrigger;
}

public TorrentSettings ToSettings ()
{
return new TorrentSettings (
AllowDht,
AllowInitialSeeding,
AllowPeerExchange,
MaximumConnections,
MaximumDownloadRate,
MaximumUploadRate,
UploadSlots,
WebSeedDelay,
WebSeedSpeedTrigger,
CreateContainingDirectory
allowDht: AllowDht,
allowInitialSeeding: AllowInitialSeeding,
allowPeerExchange: AllowPeerExchange,
createContainingDirectory: CreateContainingDirectory,
maximumConnections: MaximumConnections,
maximumDownloadRate: MaximumDownloadRate,
maximumUploadRate: MaximumUploadRate,
uploadSlots: UploadSlots
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ public TimeSpan ConnectionTimeout {

#region Constructors

public HttpPeerConnection (ITorrentManagerInfo torrentData, Factories requestCreator, Uri uri)
public HttpPeerConnection (ITorrentManagerInfo torrentData, TimeSpan connectionTimeout, Factories requestCreator, Uri uri)
{
ConnectionTimeout = TimeSpan.FromSeconds (10);
ConnectionTimeout = connectionTimeout;
RequestCreator = requestCreator;
TorrentData = torrentData ?? throw new ArgumentNullException (nameof (torrentData));
Uri = uri;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public void Setup ()

rig = TestRig.CreateMultiFile ();

connection = new HttpPeerConnection (rig.Manager, rig.Engine.Factories, new Uri (ListenerURL));
connection = new HttpPeerConnection (rig.Manager, rig.Engine.Settings.WebSeedConnectionTimeout, rig.Engine.Factories, new Uri (ListenerURL));
rig.Manager.UnhashedPieces.SetAll (false);

id = new PeerId (new Peer ("this is my id", connection.Uri), connection, new BitField (rig.Manager.Torrent.PieceCount ()).SetAll (true));
Expand Down Expand Up @@ -380,7 +380,7 @@ public async Task SingleFileTorrent ()
rig.Torrent.HttpSeeds.Add (new Uri ($"{ListenerURL}File1.exe"));

Uri url = rig.Torrent.HttpSeeds[0];
connection = new HttpPeerConnection (rig.Manager, rig.Engine.Factories, url);
connection = new HttpPeerConnection (rig.Manager, rig.Engine.Settings.WebSeedConnectionTimeout, rig.Engine.Factories, url);
rig.Manager.UnhashedPieces.SetAll (false);

id = new PeerId (new Peer ("this is my id", connection.Uri), id.Connection, new BitField (rig.Manager.Torrent.PieceCount ()).SetAll (true));
Expand Down

0 comments on commit 35c1c43

Please sign in to comment.