public QueuedIO(IPeerConnection connection, SocketMemory buffer, IRateLimiter rateLimiter, ReusableTaskCompletionSource <int> tcs) { this.connection = connection; this.buffer = buffer; this.rateLimiter = rateLimiter; this.tcs = tcs; }
public new Releaser Rent(int capacity, out SocketMemory memory) { var releaser = base.Rent(capacity, out memory); memory = memory.Slice(0, capacity); return(releaser); }
/// <summary> /// Where possible we will use a SocketAsyncEventArgs object which has already had /// 'SetBuffer(byte[],int,int)' invoked on it for the given byte[]. Reusing these is /// much more efficient than constantly calling SetBuffer on a different 'SocketAsyncEventArgs' /// object. /// </summary> /// <param name="buffer">The buffer we wish to get the reusuable 'SocketAsyncEventArgs' for</param> /// <returns></returns> static SocketAsyncEventArgs GetSocketAsyncEventArgs(SocketMemory buffer) { #if NETSTANDARD2_0 if (buffer.SocketArgs.Buffer == null) { buffer.SocketArgs.Completed += Handler; } if (!MemoryMarshal.TryGetArray(buffer.Memory, out ArraySegment <byte> segment)) { throw new ArgumentException("Could not retrieve the underlying buffer"); } if (buffer.SocketArgs.Buffer == null) { buffer.SocketArgs.SetBuffer(segment.Array, segment.Offset, segment.Count); } else { buffer.SocketArgs.SetBuffer(segment.Offset, segment.Count); } #else if (buffer.SocketArgs.MemoryBuffer.IsEmpty) { buffer.SocketArgs.Completed += Handler; } buffer.SocketArgs.SetBuffer(buffer.Memory); #endif return(buffer.SocketArgs); }
public static async ReusableTask SendAsync(IPeerConnection connection, SocketMemory buffer, IRateLimiter rateLimiter, SpeedMonitor peerMonitor, SpeedMonitor managerMonitor) { await MainLoop.SwitchToThreadpool(); while (buffer.Length > 0) { int transferred; bool unlimited = rateLimiter?.Unlimited ?? true; int shouldRead = unlimited ? buffer.Length : Math.Min(ChunkLength, buffer.Length); if (rateLimiter != null && !unlimited && !rateLimiter.TryProcess(shouldRead)) { var tcs = new ReusableTaskCompletionSource <int> (); lock (sendQueue) sendQueue.Enqueue(new QueuedIO(connection, buffer.Slice(0, shouldRead), rateLimiter, tcs)); transferred = await tcs.Task.ConfigureAwait(false); } else { transferred = await connection.SendAsync(buffer.Slice(0, shouldRead)).ConfigureAwait(false); } if (transferred == 0) { throw new ConnectionClosedException("Socket send returned 0, indicating the connection has been closed."); } peerMonitor?.AddDelta(transferred); managerMonitor?.AddDelta(transferred); buffer = buffer.Slice(transferred); } }
public static async ReusableTask <(PeerMessage message, PeerMessage.Releaser releaser)> ReceiveMessageAsync(IPeerConnection connection, IEncryption decryptor, IRateLimiter rateLimiter, ConnectionMonitor peerMonitor, ConnectionMonitor managerMonitor, ITorrentData torrentData, SocketMemory buffer) { await MainLoop.SwitchToThreadpool(); int messageHeaderLength = 4; int messageBodyLength; SocketMemory messageHeaderBuffer = buffer; SocketMemory messageBuffer = buffer; ByteBufferPool.Releaser messageHeaderReleaser = default; ByteBufferPool.Releaser messageBufferReleaser = default; if (messageHeaderBuffer.IsEmpty) { messageHeaderReleaser = NetworkIO.BufferPool.Rent(messageHeaderLength, out messageHeaderBuffer); } using (messageHeaderReleaser) { await NetworkIO.ReceiveAsync(connection, messageHeaderBuffer.Slice(0, messageHeaderLength), rateLimiter, peerMonitor?.ProtocolDown, managerMonitor?.ProtocolDown).ConfigureAwait(false); decryptor.Decrypt(messageHeaderBuffer.AsSpan(0, messageHeaderLength)); messageBodyLength = Message.ReadInt(messageHeaderBuffer.AsSpan()); if (messageBodyLength < 0 || messageBodyLength > MaxMessageLength) { connection.Dispose(); throw new ProtocolException($"Invalid message length received. Value was '{messageBodyLength}'"); } if (messageBodyLength == 0) { return(KeepAliveMessage.Instance, default);
public ReusableTask <int> SendAsync(SocketMemory buffer) { SocketAsyncEventArgs args = GetSocketAsyncEventArgs(buffer); args.UserToken = SendTcs; AsyncFlowControl?control = null; if (!ExecutionContext.IsFlowSuppressed()) { control = ExecutionContext.SuppressFlow(); } try { if (!Socket.SendAsync(args)) { SendTcs.SetResult(buffer.Length); } } catch (ObjectDisposedException) { SendTcs.SetResult(0); } finally { control?.Undo(); } return(SendTcs.Task); }
/// <summary> /// /// </summary> /// <param name="manager">The torrent which the peer is associated with.</param> /// <param name="id">The peer whose message queue you want to start processing</param> internal async void TryProcessQueue(TorrentManager manager, PeerId id) { if (!id.MessageQueue.BeginProcessing()) { return; } await MainLoop.SwitchToThreadpool(); ByteBufferPool.Releaser socketMemoryReleaser = default; SocketMemory socketMemory = default; try { while (id.MessageQueue.TryDequeue(out PeerMessage msg, out PeerMessage.Releaser msgReleaser)) { using var autorelease = msgReleaser; if (socketMemory.IsEmpty || socketMemory.Length < msg.ByteLength) { socketMemoryReleaser.Dispose(); (socketMemoryReleaser, socketMemory) = NetworkIO.BufferPool.Rent(msg.ByteLength); } var buffer = socketMemory.Slice(0, msg.ByteLength); if (msg is PieceMessage pm) { pm.SetData((default, buffer.Memory.Slice(buffer.Length - pm.RequestLength)));
protected async ReusableTask ReceiveMessageAsync(SocketMemory buffer) { if (buffer.Length == 0) { return; } if (!initialBuffer.IsEmpty) { int toCopy = Math.Min(initialBuffer.Length, buffer.Length); initialBuffer.Span.Slice(0, toCopy).CopyTo(buffer.AsSpan()); initialBuffer = initialBuffer.Slice(toCopy); if (toCopy != buffer.Length) { await NetworkIO.ReceiveAsync(socket, buffer.Slice(toCopy, buffer.Length - toCopy), null, null, null).ConfigureAwait(false); bytesReceived += buffer.Length - toCopy; } } else { await NetworkIO.ReceiveAsync(socket, buffer, null, null, null).ConfigureAwait(false); bytesReceived += buffer.Length; } }
internal async void ReceiveMessagesAsync(IPeerConnection connection, IEncryption decryptor, RateLimiterGroup downloadLimiter, ConnectionMonitor monitor, TorrentManager torrentManager, PeerId id) { await MainLoop.SwitchToThreadpool(); SocketMemory currentBuffer = default; SocketMemory smallBuffer = default; ByteBufferPool.Releaser smallReleaser = default; SocketMemory largeBuffer = default; ByteBufferPool.Releaser largeReleaser = default; try { while (true) { if (id.AmRequestingPiecesCount == 0) { if (!largeBuffer.IsEmpty) { largeReleaser.Dispose(); largeReleaser = default; largeBuffer = currentBuffer = default; } if (smallBuffer.IsEmpty) { smallReleaser = NetworkIO.BufferPool.Rent(ByteBufferPool.SmallMessageBufferSize, out smallBuffer); currentBuffer = smallBuffer; } } else { if (!smallBuffer.IsEmpty) { smallReleaser.Dispose(); smallReleaser = default; smallBuffer = currentBuffer = default; } if (largeBuffer.IsEmpty) { largeReleaser = NetworkIO.BufferPool.Rent(ByteBufferPool.LargeMessageBufferSize, out largeBuffer); currentBuffer = largeBuffer; } } (PeerMessage message, PeerMessage.Releaser releaser) = await PeerIO.ReceiveMessageAsync(connection, decryptor, downloadLimiter, monitor, torrentManager.Monitor, torrentManager, currentBuffer).ConfigureAwait(false); HandleReceivedMessage(id, torrentManager, message, releaser); } } catch { await ClientEngine.MainLoop; CleanupSocket(torrentManager, id); } finally { smallReleaser.Dispose(); largeReleaser.Dispose(); } }
private async Task CompleteSendOrReceiveFirst(SocketMemory buffer) { var allRequests = new List <RequestMessage> (); var requestsBuffer = requests.Encode().AsMemory(); while (requestsBuffer.Length > 0) { var message = (RequestMessage)PeerMessage.DecodeMessage(requestsBuffer.Span, null).message; allRequests.Add(message); requestsBuffer = requestsBuffer.Slice(message.ByteLength); } while (allRequests.Count > 0) { int size = Message.ReadInt(buffer.Span); await NetworkIO.ReceiveAsync(connection, buffer.Slice(4, size), null, null, null); PieceMessage m = (PieceMessage)PeerMessage.DecodeMessage(buffer.AsSpan(0, size + 4), rig.Manager).message; var request = allRequests[0]; Assert.AreEqual(request.PieceIndex, m.PieceIndex, "#1"); Assert.AreEqual(request.RequestLength, m.RequestLength, "#1"); Assert.AreEqual(request.StartOffset, m.StartOffset, "#1"); for (int i = 0; i < request.RequestLength; i++) { if (buffer.Span[i + 13] != (byte)(m.PieceIndex * rig.Torrent.PieceLength + m.StartOffset + i)) { throw new Exception("Corrupted data received"); } } allRequests.RemoveAt(0); if (allRequests.Count == 0) { break; } else { await NetworkIO.ReceiveAsync(connection, buffer.Slice(0, 4), null, null, null);; } } Uri baseUri = new Uri(ListenerURL); baseUri = new Uri(baseUri, $"{rig.Manager.Torrent.Name}/"); if (rig.Manager.Torrent.Files.Count > 1) { Assert.AreEqual(new Uri(baseUri, rig.Manager.Torrent.Files[0].Path), requestedUrl[0]); Assert.AreEqual(new Uri(baseUri, rig.Manager.Torrent.Files[1].Path), requestedUrl[1]); } }
public async ReusableTask <int> ReceiveAsync(SocketMemory buffer) { if (SlowConnection) { buffer = buffer.Slice(0, Math.Min(88, buffer.Length)); } var result = await ReadStream.ReadAsync(buffer.Memory); Receives.Add(result); return(ManualBytesReceived ?? result); }
public async ReusableTask <int> SendAsync(SocketMemory buffer) { if (SlowConnection) { buffer = buffer.Slice(0, Math.Min(88, buffer.Length)); } var data = buffer.Memory.ToArray(); await WriteStream.WriteAsync(data, 0, data.Length, CancellationToken.None); Sends.Add(buffer.Length); return(ManualBytesSent ?? buffer.Length); }
async Task Send(SocketMemory buffer, int maxBytesPerChunk = -1) { if (maxBytesPerChunk == -1) { await NetworkIO.SendAsync(connection, buffer, null, null, null); } else { while (buffer.Length > 0) { var toSend = Math.Min(maxBytesPerChunk, buffer.Length); await NetworkIO.SendAsync(connection, buffer.Slice(0, toSend), null, null, null); buffer = buffer.Slice(toSend); } } }
public static ReusableTask SendAsync(IPeerConnection connection, SocketMemory buffer) { return(SendAsync(connection, buffer, null, null, null)); }
public ReusableTask <int> SendAsync(SocketMemory buffer) { return(ReusableTask.FromResult(0)); }