Remove warnings, replace BIP79 by Payjoin, Fix strange error in Accept loop

This commit is contained in:
nicolas.dorier
2020-04-09 20:25:17 +09:00
parent 95644f8884
commit e3f6de8472
4 changed files with 52 additions and 49 deletions

View File

@@ -101,7 +101,7 @@ namespace BTCPayServer.Tests
[Fact] [Fact]
[Trait("Selenium", "Selenium")] [Trait("Selenium", "Selenium")]
public async Task CanUseBIP79Client() public async Task CanUsePayjoinViaUI()
{ {
using (var s = SeleniumTester.Create()) using (var s = SeleniumTester.Create())
{ {
@@ -223,7 +223,7 @@ namespace BTCPayServer.Tests
[Fact] [Fact]
[Trait("Integration", "Integration")] [Trait("Integration", "Integration")]
public async Task CanUseBIP79FeeCornerCase() public async Task CanUsePayjoinFeeCornerCase()
{ {
using (var tester = ServerTester.Create()) using (var tester = ServerTester.Create())
{ {
@@ -392,7 +392,7 @@ namespace BTCPayServer.Tests
[Fact(Timeout = TestTimeout)] [Fact(Timeout = TestTimeout)]
[Trait("Integration", "Integration")] [Trait("Integration", "Integration")]
public async Task CanUseBIP79() public async Task CanUsePayjoin()
{ {
using (var tester = ServerTester.Create()) using (var tester = ServerTester.Create())
{ {

View File

@@ -126,7 +126,7 @@ namespace BTCPayServer.Controllers
.GetMetadataAsync<string>(derivationScheme.AccountDerivation, .GetMetadataAsync<string>(derivationScheme.AccountDerivation,
WellknownMetadataKeys.MasterHDKey); WellknownMetadataKeys.MasterHDKey);
return await SignWithSeed(walletId, return SignWithSeed(walletId,
new SignWithSeedViewModel() {SeedOrKey = extKey, PSBT = psbt.ToBase64(), PayJoinEndpointUrl = vm.PayJoinEndpointUrl}); new SignWithSeedViewModel() {SeedOrKey = extKey, PSBT = psbt.ToBase64(), PayJoinEndpointUrl = vm.PayJoinEndpointUrl});
} }

View File

@@ -611,7 +611,7 @@ namespace BTCPayServer.Controllers
var extKey = await ExplorerClientProvider.GetExplorerClient(network) var extKey = await ExplorerClientProvider.GetExplorerClient(network)
.GetMetadataAsync<string>(derivationScheme.AccountDerivation, WellknownMetadataKeys.MasterHDKey, cancellation); .GetMetadataAsync<string>(derivationScheme.AccountDerivation, WellknownMetadataKeys.MasterHDKey, cancellation);
return await SignWithSeed(walletId, new SignWithSeedViewModel() return SignWithSeed(walletId, new SignWithSeedViewModel()
{ {
PayJoinEndpointUrl = vm.PayJoinEndpointUrl, PayJoinEndpointUrl = vm.PayJoinEndpointUrl,
SeedOrKey = extKey, SeedOrKey = extKey,
@@ -701,7 +701,7 @@ namespace BTCPayServer.Controllers
[HttpPost] [HttpPost]
[Route("{walletId}/vault")] [Route("{walletId}/vault")]
public async Task<IActionResult> WalletSendVault([ModelBinder(typeof(WalletIdModelBinder))] public IActionResult WalletSendVault([ModelBinder(typeof(WalletIdModelBinder))]
WalletId walletId, WalletSendVaultModel model) WalletId walletId, WalletSendVaultModel model)
{ {
return RedirectToWalletPSBTReady(model.PSBT, originalPsbt: model.OriginalPSBT, payJoinEndpointUrl: model.PayJoinEndpointUrl); return RedirectToWalletPSBTReady(model.PSBT, originalPsbt: model.OriginalPSBT, payJoinEndpointUrl: model.PayJoinEndpointUrl);
@@ -777,7 +777,7 @@ namespace BTCPayServer.Controllers
[HttpPost] [HttpPost]
[Route("{walletId}/ledger")] [Route("{walletId}/ledger")]
public async Task<IActionResult> SubmitLedger([ModelBinder(typeof(WalletIdModelBinder))] public IActionResult SubmitLedger([ModelBinder(typeof(WalletIdModelBinder))]
WalletId walletId, WalletSendLedgerModel model) WalletId walletId, WalletSendLedgerModel model)
{ {
return RedirectToWalletPSBTReady(model.PSBT); return RedirectToWalletPSBTReady(model.PSBT);
@@ -795,7 +795,7 @@ namespace BTCPayServer.Controllers
} }
[HttpPost("{walletId}/psbt/seed")] [HttpPost("{walletId}/psbt/seed")]
public async Task<IActionResult> SignWithSeed([ModelBinder(typeof(WalletIdModelBinder))] public IActionResult SignWithSeed([ModelBinder(typeof(WalletIdModelBinder))]
WalletId walletId, SignWithSeedViewModel viewModel) WalletId walletId, SignWithSeedViewModel viewModel)
{ {
if (!ModelState.IsValid) if (!ModelState.IsValid)

View File

@@ -29,6 +29,7 @@ namespace BTCPayServer.HostedServices
{ {
class ProxyConnection class ProxyConnection
{ {
public ServerContext ServerContext;
public Socket ClientSocket; public Socket ClientSocket;
public Socket SocksSocket; public Socket SocksSocket;
public CancellationToken CancellationToken; public CancellationToken CancellationToken;
@@ -41,25 +42,41 @@ namespace BTCPayServer.HostedServices
CancellationTokenSource.Dispose(); CancellationTokenSource.Dispose();
} }
} }
class ServerContext
{
public EndPoint SocksEndpoint;
public Socket ServerSocket;
public CancellationToken CancellationToken;
public int ConnectionCount;
}
private readonly BTCPayServerOptions _opts; private readonly BTCPayServerOptions _opts;
public Socks5HttpProxyServer(Configuration.BTCPayServerOptions opts) public Socks5HttpProxyServer(Configuration.BTCPayServerOptions opts)
{ {
_opts = opts; _opts = opts;
} }
private Socket _ServerSocket; private ServerContext _ServerContext;
private CancellationTokenSource _Cts; private CancellationTokenSource _Cts;
public Task StartAsync(CancellationToken cancellationToken) public Task StartAsync(CancellationToken cancellationToken)
{ {
if (_opts.SocksEndpoint is null) if (_opts.SocksEndpoint is null || _ServerContext != null)
return Task.CompletedTask; return Task.CompletedTask;
_Cts = new CancellationTokenSource(); _Cts = new CancellationTokenSource();
_ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_ServerSocket.Bind(new IPEndPoint(IPAddress.Loopback, 0)); socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Port = ((IPEndPoint)(_ServerSocket.LocalEndPoint)).Port; socket.Bind(new IPEndPoint(IPAddress.Loopback, 0));
Port = ((IPEndPoint)(socket.LocalEndPoint)).Port;
Uri = new Uri($"http://127.0.0.1:{Port}"); Uri = new Uri($"http://127.0.0.1:{Port}");
_ServerSocket.Listen(5); socket.Listen(5);
_ServerSocket.BeginAccept(Accept, null); _ServerContext = new ServerContext()
{
SocksEndpoint = _opts.SocksEndpoint,
ServerSocket = socket,
CancellationToken = _Cts.Token,
ConnectionCount = 0
};
socket.BeginAccept(Accept, _ServerContext);
Logs.PayServer.LogInformation($"Internal Socks HTTP Proxy listening at {Uri}"); Logs.PayServer.LogInformation($"Internal Socks HTTP Proxy listening at {Uri}");
return Task.CompletedTask; return Task.CompletedTask;
} }
@@ -67,47 +84,49 @@ namespace BTCPayServer.HostedServices
public int Port { get; private set; } public int Port { get; private set; }
public Uri Uri { get; private set; } public Uri Uri { get; private set; }
void Accept(IAsyncResult ar) static void Accept(IAsyncResult ar)
{ {
var ctx = (ServerContext)ar.AsyncState;
Socket clientSocket = null; Socket clientSocket = null;
try try
{ {
clientSocket = _ServerSocket.EndAccept(ar); clientSocket = ctx.ServerSocket.EndAccept(ar);
} }
catch (ObjectDisposedException e) catch (ObjectDisposedException)
{ {
return; return;
} }
if (_Cts.IsCancellationRequested) if (ctx.CancellationToken.IsCancellationRequested)
{ {
Dispose(clientSocket); Dispose(clientSocket);
return; return;
} }
var toSocksProxy = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); var toSocksProxy = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var connectionCts = CancellationTokenSource.CreateLinkedTokenSource(_Cts.Token); var connectionCts = CancellationTokenSource.CreateLinkedTokenSource(ctx.CancellationToken);
toSocksProxy.BeginConnect(_opts.SocksEndpoint, ConnectToSocks, new ProxyConnection() toSocksProxy.BeginConnect(ctx.SocksEndpoint, ConnectToSocks, new ProxyConnection()
{ {
ServerContext = ctx,
ClientSocket = clientSocket, ClientSocket = clientSocket,
SocksSocket = toSocksProxy, SocksSocket = toSocksProxy,
CancellationToken = connectionCts.Token, CancellationToken = connectionCts.Token,
CancellationTokenSource = connectionCts CancellationTokenSource = connectionCts
}); });
_ServerSocket.BeginAccept(Accept, null); ctx.ServerSocket.BeginAccept(Accept, ctx);
} }
void ConnectToSocks(IAsyncResult ar) static void ConnectToSocks(IAsyncResult ar)
{ {
var connection = (ProxyConnection)ar.AsyncState; var connection = (ProxyConnection)ar.AsyncState;
try try
{ {
connection.SocksSocket.EndConnect(ar); connection.SocksSocket.EndConnect(ar);
} }
catch (Exception e) catch (Exception)
{ {
connection.Dispose(); connection.Dispose();
return; return;
} }
Interlocked.Increment(ref connectionCount); Interlocked.Increment(ref connection.ServerContext.ConnectionCount);
var pipe = new Pipe(PipeOptions.Default); var pipe = new Pipe(PipeOptions.Default);
CancellationTokenSource.CreateLinkedTokenSource(connection.CancellationToken); CancellationTokenSource.CreateLinkedTokenSource(connection.CancellationToken);
var reading = FillPipeAsync(connection.ClientSocket, pipe.Writer, connection.CancellationToken) var reading = FillPipeAsync(connection.ClientSocket, pipe.Writer, connection.CancellationToken)
@@ -118,12 +137,11 @@ namespace BTCPayServer.HostedServices
.ContinueWith(_ => .ContinueWith(_ =>
{ {
connection.Dispose(); connection.Dispose();
Interlocked.Decrement(ref connectionCount); Interlocked.Decrement(ref connection.ServerContext.ConnectionCount);
}, TaskScheduler.Default); }, TaskScheduler.Default);
} }
private int connectionCount = 0; public int ConnectionCount => _ServerContext is ServerContext s ? s.ConnectionCount : 0;
public int ConnectionCount => connectionCount;
private static async Task ReadPipeAsync(Socket socksSocket, Socket clientSocket, PipeReader reader, CancellationToken cancellationToken) private static async Task ReadPipeAsync(Socket socksSocket, Socket clientSocket, PipeReader reader, CancellationToken cancellationToken)
{ {
bool handshaked = false; bool handshaked = false;
@@ -295,43 +313,28 @@ namespace BTCPayServer.HostedServices
{ {
while (true) while (true)
{ {
// Allocate at least 512 bytes from the PipeWriter
Memory<byte> memory = writer.GetMemory(BufferSize); Memory<byte> memory = writer.GetMemory(BufferSize);
try
{
int bytesRead = await socket.ReceiveAsync(memory, SocketFlags.None, cancellationToken); int bytesRead = await socket.ReceiveAsync(memory, SocketFlags.None, cancellationToken);
if (bytesRead == 0) if (bytesRead == 0)
{ {
break; break;
} }
// Tell the PipeWriter how much was read from the Socket
writer.Advance(bytesRead); writer.Advance(bytesRead);
}
catch (Exception ex)
{
//LogError(ex);
break;
}
// Make the data available to the PipeReader
FlushResult result = await writer.FlushAsync(cancellationToken); FlushResult result = await writer.FlushAsync(cancellationToken);
if (result.IsCompleted) if (result.IsCompleted)
{ {
break; break;
} }
} }
// Tell the PipeReader that there's no more data coming
writer.Complete(); writer.Complete();
} }
public Task StopAsync(CancellationToken cancellationToken) public Task StopAsync(CancellationToken cancellationToken)
{ {
if (_ServerSocket is Socket) if (_ServerContext is ServerContext ctx)
{ {
_Cts.Cancel(); _Cts.Cancel();
Dispose(_ServerSocket); Dispose(ctx.ServerSocket);
Logs.PayServer.LogInformation($"Internal Socks HTTP Proxy closed"); Logs.PayServer.LogInformation($"Internal Socks HTTP Proxy closed");
} }
return Task.CompletedTask; return Task.CompletedTask;