Beispiel #1
0
        public void Run()
        {
            Log.InfoAsync($"{nameof(TcpRelay)} Starting");
            AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;

            RelayConnectedServicesManager.LoadState().GetAwaiter().GetResult();
            RelayConnectedServicesManager.StartExpireStatistics(canceller.Token);

            Log.InfoAsync($"{nameof(TcpRelay)} Opened On {ConnectionString}");

            Open();

            Log.InfoAsync($"{nameof(TcpRelay)} Closed On {ConnectionString}");
        }
 public void FlagConnectionFailed()
 {
     lock (failureLock)
     {
         if (lastFailure < DateTime.UtcNow.AddMilliseconds(failureWaitMilliseconds))
         {
             failures++;
             lastFailure = DateTime.UtcNow;
         }
         if (failures >= maxFailures)
         {
             RelayConnectedServicesManager.Remove(this.Url);
             if (Resolver.TryGet(out ILoggingProvider logger))
             {
                 logger.InfoAsync($"Service {this.Url} Failed {maxFailures} times, removing...");
             }
         }
     }
 }
Beispiel #3
0
        protected override async void Handle(TcpClient client, CancellationToken cancellationToken)
        {
            TcpClient             outgoingClient = null;
            CQRSProtocolType?     protocolType   = null;
            RelayConnectedService service        = null;
            Stopwatch             stopwatch      = null;
            bool responseStarted = false;

            var bufferOwner = BufferArrayPool <byte> .Rent(bufferLength);

            var buffer = bufferOwner.AsMemory();

            Stream incommingStream           = null;
            Stream incommingBodyStream       = null;
            Stream outgoingWritingBodyStream = null;

            Stream outgoingStream             = null;
            Stream outgoingBodyStream         = null;
            Stream incommingWritingBodyStream = null;

            try
            {
                incommingStream = client.GetStream();

                var headerPosition = 0;
                var headerLength   = 0;
                var headerEnd      = false;
                while (headerLength < TcpCommon.MaxProtocolHeaderPrefixLength)
                {
                    if (headerLength == buffer.Length)
                    {
                        throw new Exception($"{nameof(TcpRelay)} Header Too Long");
                    }

                    headerLength += await incommingStream.ReadAsync(buffer.Slice(headerPosition, buffer.Length - headerPosition), cancellationToken);
                }
                protocolType = TcpCommon.ReadProtocol(buffer.Span);

                string providerType;

                switch (protocolType.Value)
                {
                case CQRSProtocolType.TcpRaw:
                {
                    headerEnd = TcpRawCommon.ReadToHeaderEnd(buffer, ref headerPosition, headerLength);
                    while (!headerEnd)
                    {
                        if (headerLength == buffer.Length)
                        {
                            throw new Exception($"{nameof(TcpRelay)} Header Too Long");
                        }

                        headerLength += await incommingStream.ReadAsync(buffer.Slice(headerLength, buffer.Length - headerLength), cancellationToken);

                        headerEnd = TcpRawCommon.ReadToHeaderEnd(buffer, ref headerPosition, headerLength);
                    }
                    var header = TcpRawCommon.ReadHeader(buffer, headerPosition, headerLength);
                    providerType        = header.ProviderType;
                    incommingBodyStream = new TcpRawProtocolBodyStream(incommingStream, header.BodyStartBuffer, true);
                    break;
                }

                case CQRSProtocolType.Http:
                {
                    headerEnd = HttpCommon.ReadToHeaderEnd(buffer, ref headerPosition, headerLength);
                    while (!headerEnd)
                    {
                        if (headerLength == buffer.Length)
                        {
                            throw new Exception($"{nameof(TcpRelay)} Header Too Long");
                        }

                        headerLength += await incommingStream.ReadAsync(buffer.Slice(headerLength, buffer.Length - headerLength), cancellationToken);

                        headerEnd = HttpCommon.ReadToHeaderEnd(buffer, ref headerPosition, headerLength);
                    }
                    var header = HttpCommon.ReadHeader(buffer, headerPosition, headerLength);
                    providerType        = header.ProviderType;
                    incommingBodyStream = new HttpProtocolBodyStream(header.ContentLength, incommingStream, header.BodyStartBuffer, true);

                    if (header.RelayServiceAddRemove.HasValue)
                    {
                        if (header.RelayKey != relayKey)
                        {
                            throw new SecurityException("Invalid Relay Key");
                        }

                        var serviceInfo = await System.Text.Json.JsonSerializer.DeserializeAsync <ServiceInfo>(incommingBodyStream);

                        await incommingBodyStream.DisposeAsync();

                        incommingBodyStream = null;

                        if (header.RelayServiceAddRemove == true)
                        {
                            RelayConnectedServicesManager.AddOrUpdate(serviceInfo);
                        }
                        else
                        {
                            RelayConnectedServicesManager.Remove(serviceInfo.Url);
                        }

                        var requestHeaderLength = HttpCommon.BufferOkHeader(buffer);
                        await incommingStream.WriteAsync(buffer.Slice(0, requestHeaderLength), cancellationToken);

                        await incommingStream.FlushAsync();

                        await incommingStream.DisposeAsync();

                        incommingStream = null;
                        client.Dispose();
                        return;
                    }
                    break;
                }

                default: throw new NotImplementedException();
                }

                while (outgoingClient == null)
                {
                    service = RelayConnectedServicesManager.GetBestService(providerType);
                    if (service == null)
                    {
                        break;
                    }

                    try
                    {
                        _ = Log.TraceAsync($"Relaying {providerType} to {service.Url}");

                        var outgoingEndpoint = IPResolver.GetIPEndPoints(service.Url, 80).First();
                        if (outgoingEndpoint != null)
                        {
                            outgoingClient         = new TcpClient(outgoingEndpoint.AddressFamily);
                            outgoingClient.NoDelay = true;
                            await outgoingClient.ConnectAsync(outgoingEndpoint.Address, outgoingEndpoint.Port);

                            service.FlagConnectionSuccess();
                        }
                        else
                        {
                            service.FlagConnectionFailed();
                        }
                    }
                    catch
                    {
                        service.FlagConnectionFailed();
                    }
                }

                if (outgoingClient == null)
                {
                    _ = Log.TraceAsync($"Destination not found {providerType}");
                    switch (protocolType.Value)
                    {
                    case CQRSProtocolType.TcpRaw:
                    {
                        var requestHeaderLength = HttpCommon.BufferNotFoundHeader(buffer);
                        await incommingStream.WriteAsync(buffer.Slice(0, requestHeaderLength));

                        return;
                    }

                    case CQRSProtocolType.Http:
                    {
                        var requestHeaderLength = TcpRawCommon.BufferErrorHeader(buffer, null, default);
                        await incommingStream.WriteAsync(buffer.Slice(0, requestHeaderLength));

                        return;
                    }

                    default: throw new NotImplementedException();
                    }
                }

                outgoingStream = outgoingClient.GetStream();

                stopwatch = service.StartRequestRunning();

                responseStarted = true;
                await outgoingStream.WriteAsync(buffer.Slice(0, headerPosition), cancellationToken);

                switch (protocolType.Value)
                {
                case CQRSProtocolType.TcpRaw:
                {
                    outgoingWritingBodyStream = new TcpRawProtocolBodyStream(outgoingStream, null, true);
                    await incommingBodyStream.CopyToAsync(outgoingWritingBodyStream, cancellationToken);

                    await outgoingWritingBodyStream.FlushAsync();

                    break;
                }

                case CQRSProtocolType.Http:
                {
                    outgoingWritingBodyStream = new HttpProtocolBodyStream(null, outgoingStream, null, true);
                    await incommingBodyStream.CopyToAsync(outgoingWritingBodyStream, cancellationToken);

                    await outgoingWritingBodyStream.FlushAsync();

                    break;
                }

                default: throw new NotImplementedException();
                }

                await incommingBodyStream.DisposeAsync();

                incommingBodyStream = null;
                await outgoingWritingBodyStream.DisposeAsync();

                outgoingWritingBodyStream = null;

                //Response
                //-----------------------------------------------------------------------------------------------------------------------

                headerPosition = 0;
                headerLength   = 0;
                headerEnd      = false;
                switch (protocolType.Value)
                {
                case CQRSProtocolType.TcpRaw:
                {
                    while (!headerEnd)
                    {
                        if (headerLength == buffer.Length)
                        {
                            throw new Exception($"{nameof(TcpRelay)} Header Too Long");
                        }

                        headerLength += await outgoingStream.ReadAsync(buffer.Slice(headerLength, buffer.Length - headerLength));

                        headerEnd = TcpRawCommon.ReadToHeaderEnd(buffer, ref headerPosition, headerLength);
                    }
                    outgoingBodyStream = new TcpRawProtocolBodyStream(outgoingStream, buffer.Slice(headerPosition, headerLength - headerPosition), false);
                    break;
                }

                case CQRSProtocolType.Http:
                {
                    while (!headerEnd)
                    {
                        if (headerLength == buffer.Length)
                        {
                            throw new Exception($"{nameof(TcpRelay)} Header Too Long");
                        }

                        headerLength += await outgoingStream.ReadAsync(buffer.Slice(headerLength, buffer.Length - headerLength));

                        headerEnd = HttpCommon.ReadToHeaderEnd(buffer, ref headerPosition, headerLength);
                    }
                    var header = HttpCommon.ReadHeader(buffer, headerPosition, headerLength);
                    outgoingBodyStream = new HttpProtocolBodyStream(header.ContentLength, outgoingStream, header.BodyStartBuffer, false);
                    break;
                }
                }

                await incommingStream.WriteAsync(buffer.Slice(0, headerPosition), cancellationToken);

                switch (protocolType.Value)
                {
                case CQRSProtocolType.TcpRaw:
                {
                    incommingWritingBodyStream = new TcpRawProtocolBodyStream(incommingStream, null, false);
                    await outgoingBodyStream.CopyToAsync(incommingWritingBodyStream, cancellationToken);

                    await incommingWritingBodyStream.FlushAsync();

                    break;
                }

                case CQRSProtocolType.Http:
                {
                    incommingWritingBodyStream = new HttpProtocolBodyStream(null, incommingStream, null, false);
                    await outgoingBodyStream.CopyToAsync(incommingWritingBodyStream, cancellationToken);

                    await incommingWritingBodyStream.FlushAsync();

                    break;
                }

                default: throw new NotImplementedException();
                }

                await outgoingBodyStream.DisposeAsync();

                outgoingBodyStream = null;
                await incommingWritingBodyStream.DisposeAsync();

                incommingWritingBodyStream = null;
                outgoingClient.Dispose();
                client.Dispose();
            }
            catch (Exception ex)
            {
                if (ex is IOException ioException)
                {
                    if (ioException.InnerException != null && ioException.InnerException is SocketException socketException)
                    {
                        if (socketException.SocketErrorCode == SocketError.ConnectionAborted)
                        {
                            return;
                        }
                    }
                }

                _ = Log.ErrorAsync(null, ex);

                if (!responseStarted && incommingStream != null && protocolType.HasValue)
                {
                    try
                    {
                        switch (protocolType.Value)
                        {
                        case CQRSProtocolType.TcpRaw:
                        {
                            var requestHeaderLength = HttpCommon.BufferErrorHeader(buffer, null);
                            await incommingStream.WriteAsync(buffer.Slice(0, requestHeaderLength), cancellationToken);

                            break;
                        }

                        case CQRSProtocolType.Http:
                        {
                            var requestHeaderLength = TcpRawCommon.BufferErrorHeader(buffer, null, default);
                            await incommingStream.WriteAsync(buffer.Slice(0, requestHeaderLength), cancellationToken);

                            break;
                        }

                        default: throw new NotImplementedException();
                        }
                    }
                    catch (Exception ex2)
                    {
                        _ = Log.ErrorAsync(null, ex2);
                    }
                }

                if (outgoingWritingBodyStream != null)
                {
                    await outgoingWritingBodyStream.DisposeAsync();
                }
                if (outgoingBodyStream != null)
                {
                    await outgoingBodyStream.DisposeAsync();
                }
                if (outgoingStream != null)
                {
                    await outgoingStream.DisposeAsync();
                }
                if (incommingWritingBodyStream != null)
                {
                    await incommingWritingBodyStream.DisposeAsync();
                }
                if (incommingBodyStream != null)
                {
                    await incommingBodyStream.DisposeAsync();
                }
                if (incommingStream != null)
                {
                    await incommingStream.DisposeAsync();
                }

                if (outgoingClient != null)
                {
                    outgoingClient.Dispose();
                }

                client.Dispose();
            }
            finally
            {
                BufferArrayPool <byte> .Return(bufferOwner);

                if (service != null && stopwatch != null)
                {
                    service.EndRequestRunning(stopwatch);
                }
            }
        }