TorSocks5Client: Rename SendAndReceiveAsync to SendRequestAsync + process message based on type.
MODIFY
WalletWasabi/Tor/Socks5/TorSocks5Client.cs
WalletWasabi/Tor/Socks5/TorSocks5Client.cs
@@ -12,6 +12,7 @@ using WalletWasabi.Helpers;
using WalletWasabi.Logging;
using WalletWasabi.Tor.Http;
using WalletWasabi.Tor.Socks5.Exceptions;
+using WalletWasabi.Tor.Socks5.Models.Bases;
using WalletWasabi.Tor.Socks5.Models.Fields.ByteArrayFields;
using WalletWasabi.Tor.Socks5.Models.Fields.OctetFields;
using WalletWasabi.Tor.Socks5.Models.Messages;
@@ -126,8 +127,7 @@ namespace WalletWasabi.Tor.Socks5
// SOCKS5 client implementations.
var methods = new MethodsField(isolateStream ? MethodField.UsernamePassword : MethodField.NoAuthenticationRequired);
- byte[] sendBuffer = new VersionMethodRequest(methods).ToBytes();
- byte[] receiveBuffer = await SendAndReceiveAsync(sendBuffer, receiveBufferSize: 2, cancellationToken).ConfigureAwait(false);
+ byte[] receiveBuffer = await SendRequestAsync(new VersionMethodRequest(methods), cancellationToken).ConfigureAwait(false);
var methodSelection = new MethodSelectionResponse(receiveBuffer);
@@ -154,10 +154,8 @@ namespace WalletWasabi.Tor.Socks5
var uName = new UNameField(uName: identity);
var passwd = new PasswdField(password: identity);
var usernamePasswordRequest = new UsernamePasswordRequest(uName, passwd);
- sendBuffer = usernamePasswordRequest.ToBytes();
- Array.Clear(receiveBuffer, 0, receiveBuffer.Length);
- receiveBuffer = await SendAndReceiveAsync(sendBuffer, receiveBufferSize: 2, cancellationToken).ConfigureAwait(false);
+ receiveBuffer = await SendRequestAsync(usernamePasswordRequest, cancellationToken).ConfigureAwait(false);
var userNamePasswordResponse = new UsernamePasswordResponse(receiveBuffer);
@@ -222,10 +220,8 @@ namespace WalletWasabi.Tor.Socks5
try
{
- var connectionRequest = new TorSocks5Request(cmd: CmdField.Connect, new AddrField(host), new PortField(port));
- var sendBuffer = connectionRequest.ToBytes();
-
- var receiveBuffer = await SendAndReceiveAsync(sendBuffer, receiveBufferSize: null, cancellationToken).ConfigureAwait(false);
+ TorSocks5Request connectRequest = new(cmd: CmdField.Connect, new AddrField(host), new PortField(port));
+ byte[] receiveBuffer = await SendRequestAsync(connectRequest, cancellationToken).ConfigureAwait(false);
var connectionResponse = new TorSocks5Response(receiveBuffer);
@@ -331,17 +327,15 @@ namespace WalletWasabi.Tor.Socks5
}
/// <summary>
- /// Sends a command to the Tor Socks5 connection and reads a response.
+ /// Sends a request to the Tor SOCKS5 connection and returns a byte response.
/// </summary>
- /// <param name="sendBuffer">Sent data</param>
- /// <param name="receiveBufferSize">Optionally, number of bytes expected to be received in the reply.</param>
+ /// <param name="request">Request to send.</param>
/// <param name="cancellationToken">Cancellation token to cancel sending.</param>
/// <returns>Reply</returns>
+ /// <exception cref="ArgumentException">When <paramref name="request"/> is not supported.</exception>
/// <exception cref="TorConnectionException">When we receive no response from Tor or the response is invalid.</exception>
- private async Task<byte[]> SendAndReceiveAsync(byte[] sendBuffer, int? receiveBufferSize = null, CancellationToken cancellationToken = default)
+ private async Task<byte[]> SendRequestAsync(ByteArraySerializableBase request, CancellationToken cancellationToken = default)
{
- Guard.NotNullOrEmpty(nameof(sendBuffer), sendBuffer);
-
try
{
await AssertConnectedAsync(cancellationToken).ConfigureAwait(false);
@@ -350,32 +344,22 @@ namespace WalletWasabi.Tor.Socks5
{
var stream = TcpClient.GetStream();
- // Write data to the stream
- await stream.WriteAsync(sendBuffer.AsMemory(0, sendBuffer.Length), cancellationToken).ConfigureAwait(false);
- await stream.FlushAsync(cancellationToken).ConfigureAwait(false);
-
- // If receiveBufferSize is null, zero or negative or bigger than TcpClient.ReceiveBufferSize
- // then work with TcpClient.ReceiveBufferSize
- var tcpReceiveBuffSize = TcpClient.ReceiveBufferSize;
- var actualReceiveBufferSize = receiveBufferSize is null || receiveBufferSize <= 0 || receiveBufferSize > tcpReceiveBuffSize
- ? tcpReceiveBuffSize
- : (int)receiveBufferSize;
+ byte[] dataToSend = request.ToBytes();
- // Receive the response
- var receiveBuffer = new byte[actualReceiveBufferSize];
-
- // Read exactly "receiveBufferSize" bytes.
- if (receiveBufferSize != null)
- {
- int unreadBytes = await stream.ReadBlockAsync(receiveBuffer, receiveBufferSize.Value, cancellationToken).ConfigureAwait(false);
+ // Write data to the stream.
+ await stream.WriteAsync(dataToSend.AsMemory(0, dataToSend.Length), cancellationToken).ConfigureAwait(false);
+ await stream.FlushAsync(cancellationToken).ConfigureAwait(false);
- if (unreadBytes == receiveBufferSize.Value)
+ if (request is VersionMethodRequest or UsernamePasswordRequest)
{
- return receiveBuffer;
+ return await ReadTwoByteResponseAsync(stream, cancellationToken).ConfigureAwait(false);
}
+ else if (request is TorSocks5Request)
+ {
+ var actualReceiveBufferSize = TcpClient.ReceiveBufferSize;
- throw new TorConnectionException($"Failed to read {receiveBufferSize.Value} bytes as expected from Tor SOCKS5.");
- }
+ // Receive the response
+ var receiveBuffer = new byte[actualReceiveBufferSize];
int receiveCount = await stream.ReadAsync(receiveBuffer.AsMemory(0, actualReceiveBufferSize), cancellationToken).ConfigureAwait(false);
@@ -405,10 +389,15 @@ namespace WalletWasabi.Tor.Socks5
return builder.ToArray();
}
+ else
+ {
+ throw new ArgumentException("Not supported request type.", nameof(request));
+ }
+ }
}
catch (OperationCanceledException)
{
- Logger.LogTrace($"Send operation was canceled.");
+ Logger.LogTrace("Send operation was canceled.");
throw;
}
catch (IOException ex)

TorSocks5Client: Rename SendAndReceiveAsync to SendRequestAsync + process message based on type.