public override async Task OnConnectedAsync(ConnectionContext connection) { var ctx = new MConnectionContext(connection); try { await Handle(ctx); } catch (Exception e) { if (ctx.ConnectionClosed.IsCancellationRequested || ctx.LocalEndPoint == null || ctx.RemoteEndPoint == null) { } else { throw; } } }
private async Task Handle(MConnectionContext ctx) { ReadHandshake(ctx); if (ctx.ConnectionClosed.IsCancellationRequested) { return; } _logger.LogInformation( $"Received handshake, {ctx.ProtocolVersion}, {ctx.ServerAddress}:{ctx.Port}"); bool isBackendUp = true; using var backendClient = new TcpClient(); backendClient.NoDelay = true; var connectAttempt = backendClient.BeginConnect(_hostname, _port, null, null); isBackendUp = connectAttempt.AsyncWaitHandle.WaitOne(100); if (isBackendUp) { backendClient.EndConnect(connectAttempt); } if (ctx.Stage == 1 && !isBackendUp) { ctx.Items["flush"] = false; ctx.Items["close"] = false; while (!ctx.ConnectionClosed.IsCancellationRequested) { ReadResult readResult; try { readResult = await ctx.Transport.Input.ReadAsync(); } catch (Exception e) { return; } if (readResult.IsCanceled || readResult.IsCompleted) { _logger.LogInformation("Connection Closed"); return; } var buffer = readResult.Buffer; HandlePacket(buffer, ctx); if ((bool)ctx.Items["flush"]) { await ctx.Transport.Output.FlushAsync(); ctx.Items["flush"] = false; } if ((bool)ctx.Items["close"] /* we don't specifically close, we just hand it back to kestrel to deal with */) { return; } } } await using var backendStream = backendClient.GetStream(); WriteHandshake(backendStream, ctx.ProtocolVersion, ctx.ServerAddress, ctx.Port, ctx.Stage); var reader = PipeReader.Create(backendStream); var writer = PipeWriter.Create(backendStream); await Task.WhenAny(ctx.Transport.Input.CopyToAsync(writer), reader.CopyToAsync(ctx.Transport.Output)); await reader.CompleteAsync(); await writer.CompleteAsync(); }