Skip to content

Commit 0abb8c0

Browse files
committed
Tweak prior commit to raise an error instead
Use the original logic to detect when non-sequential requests are made, and raise an error instead of handling it gracefully. By default blocks are effectively random, and this is a bad access pattern for many web servers. The piece picker should be requesting a bunch of sequential blocks, which should be converted into a single large http request, which (in turn) should be better for the http server and also the library.
1 parent ad628e8 commit 0abb8c0

File tree

1 file changed

+22
-14
lines changed

1 file changed

+22
-14
lines changed

src/MonoTorrent.Client/MonoTorrent.Connections/HttpPeerConnection.cs

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
using System.Threading;
3636
using System.Threading.Tasks;
3737

38+
using MonoTorrent.Logging;
3839
using MonoTorrent.Messages;
3940
using MonoTorrent.Messages.Peer;
4041

@@ -44,6 +45,8 @@ namespace MonoTorrent.Connections.Peer
4445
{
4546
sealed class HttpPeerConnection : IPeerConnection
4647
{
48+
static readonly Logger Log = Logger.Create (nameof (HttpPeerConnection));
49+
4750
static readonly Uri PaddingFileUri = new Uri ("http://__paddingfile__");
4851

4952
class HttpRequestData
@@ -305,14 +308,20 @@ public async ReusableTask<int> SendAsync (Memory<byte> socketBuffer)
305308
{
306309
SendResult = new TaskCompletionSource<object?> ();
307310

311+
var info = TorrentData.TorrentInfo;
308312
List<BlockInfo> bundle = DecodeMessages (socketBuffer.Span);
309-
if (bundle.Count > 0) {
310-
RequestMessages.AddRange (bundle);
311-
CreateWebRequests (RequestMessages.ToArray ());
312-
} else {
313+
314+
// If the messages in the send buffer are anything *other* than piece request messages,
315+
// just pretend the bytes were sent and everything was fine.
316+
if (bundle.Count == 0 || info == null)
313317
return socketBuffer.Length;
314-
}
315318

319+
// Otherwise, if there were 1 or more piece request messages, convert these to HTTP requests.
320+
// and only mark the bytes as successfully sent after all webrequests have run to completion
321+
// and the data has been received.
322+
RequestMessages.AddRange (bundle);
323+
ValidateWebRequests (info, RequestMessages.ToArray ());
324+
CreateWebRequestsForSequentialRange (RequestMessages[0], RequestMessages[RequestMessages.Count - 1]);
316325
ReceiveWaiter.Set ();
317326
await SendResult.Task;
318327
return socketBuffer.Length;
@@ -331,22 +340,22 @@ static List<BlockInfo> DecodeMessages (ReadOnlySpan<byte> buffer)
331340
return messages;
332341
}
333342

334-
void CreateWebRequests (BlockInfo[] blocks)
343+
static void ValidateWebRequests (ITorrentInfo torrentInfo, BlockInfo[] blocks)
335344
{
336345
if (blocks.Length > 0) {
337346
BlockInfo startBlock = blocks[0];
338347
BlockInfo currentBlock = startBlock;
339348
for (int i = 1; i < blocks.Length; i++) {
340349
BlockInfo previousBlock = blocks[i - 1];
341350
currentBlock = blocks[i];
342-
long endOffsetOfPreviousEndBlock = TorrentData.TorrentInfo!.PieceIndexToByteOffset (previousBlock.PieceIndex) + previousBlock.StartOffset + previousBlock.RequestLength;
343-
long startOffsetOfCurrentBlock = TorrentData.TorrentInfo!.PieceIndexToByteOffset (currentBlock.PieceIndex) + currentBlock.StartOffset;
351+
long endOffsetOfPreviousEndBlock = torrentInfo.PieceIndexToByteOffset (previousBlock.PieceIndex) + previousBlock.StartOffset + previousBlock.RequestLength;
352+
long startOffsetOfCurrentBlock = torrentInfo.PieceIndexToByteOffset (currentBlock.PieceIndex) + currentBlock.StartOffset;
344353
if (endOffsetOfPreviousEndBlock != startOffsetOfCurrentBlock) {
345-
CreateWebRequestsForSequentialRange (startBlock, previousBlock);
346-
startBlock = currentBlock;
354+
var msg = "Piece requests made from HTTP peers must be a strictly sequential range of blocks. The range must be 1 or more blocks long.";
355+
Log.Error (msg);
356+
throw new InvalidOperationException (msg);
347357
}
348358
}
349-
CreateWebRequestsForSequentialRange (startBlock, currentBlock);
350359
}
351360
}
352361

@@ -369,11 +378,10 @@ void CreateWebRequestsForSequentialRange (BlockInfo start, BlockInfo end)
369378
if (count == 0)
370379
break;
371380

372-
var lengthWithPadding = file.Length + file.Padding;
373381
// If the first byte of data is from the next file, move to the next file immediately
374382
// and adjust start offset to be relative to that file.
375-
if (startOffset >= lengthWithPadding) {
376-
startOffset -= lengthWithPadding;
383+
if (startOffset >= file.Length + file.Padding) {
384+
startOffset -= file.Length + file.Padding;
377385
continue;
378386
}
379387

0 commit comments

Comments
 (0)