/// <summary> /// Initializes a new instance of the <see cref="PeerCommunicator" /> class. /// </summary> /// <param name="throttlingManager">The throttling manager.</param> /// <param name="tcp">The TCP.</param> public PeerCommunicator(ThrottlingManager throttlingManager, TcpClient tcp) { throttlingManager.CannotBeNull(); tcp.CannotBeNull(); this.PieceData = null; this.tm = throttlingManager; this.tcp = tcp; var data = new AsyncReadData(this.tcp.ReceiveBufferSize); this.stream = this.tcp.GetStream(); this.stream.BeginRead(data.Buffer, data.OffsetStart, data.Buffer.Length, this.Receive, data); this.Endpoint = this.tcp.Client.RemoteEndPoint as IPEndPoint; }
/// <summary> /// Asynchronous write callback. /// </summary> /// <param name="ar">The async result.</param> private void Receive(IAsyncResult ar) { AsyncReadData data = ar.AsyncState as AsyncReadData; int bytesRead = 0; int offset = data.OffsetStart; PeerMessage message; PieceMessage pieceMessage; bool isIncomplete; lock (this.locker) { if (!this.IsDisposed) { try { // read data bytesRead = this.stream.EndRead(ar); if (bytesRead > 0) { data.OffsetEnd += bytesRead; // walk through the array and try to decode messages while (offset <= data.OffsetEnd) { if (PieceMessage.TryDecode(data.Buffer, ref offset, data.OffsetEnd, out pieceMessage, out isIncomplete, this.PieceData)) { // successfully decoded message this.OnMessageReceived(this, new PeerMessgeReceivedEventArgs((PeerMessage)pieceMessage)); // remember where we left off data.OffsetStart = offset; } else if (PeerMessage.TryDecode(data.Buffer, ref offset, data.OffsetEnd, out message, out isIncomplete)) { // successfully decoded message this.OnMessageReceived(this, new PeerMessgeReceivedEventArgs(message)); // remember where we left off data.OffsetStart = offset; } else if (isIncomplete) { // message of variable length is present but incomplete -> stop advancing break; } else { // move to next byte offset++; } } if (data.OffsetStart == data.OffsetEnd) { // reset offset data.OffsetStart = 0; data.OffsetEnd = 0; } else if (data.OffsetStart > 0 && data.OffsetStart < data.OffsetEnd) { // move data to beginning of the buffere for (int i = data.OffsetStart; i < data.OffsetEnd; i++) { data.Buffer[i - data.OffsetStart] = data.Buffer[i]; } // reset offset data.OffsetEnd = data.OffsetEnd - data.OffsetStart; data.OffsetStart = 0; } else if (data.OffsetStart > data.OffsetEnd) { throw new PeerWireProtocolException("Invalid data."); } this.tm.Read(bytesRead); // resume reading if (!this.IsDisposed) { this.stream.BeginRead(data.Buffer, data.OffsetEnd, data.Buffer.Length - data.OffsetEnd, this.Receive, data); } } else { // we received no data Debug.WriteLine($"received no data from {this.Endpoint}"); } } catch (IOException ex) { Debug.WriteLine($"could not read data from {this.Endpoint}: {ex.Message}"); this.OnCommunicationError(this, new CommunicationErrorEventArgs(ex.Message)); } } } }