Skip to content

sockets end in close_wait state after some time #29

Description

@GopinathSadasivam

Looks like we are missing a time-out on stream reader in uhttpsharp\HttpClient.cs

When remote http client gets disconnected due to some network issues (or because of proxies in between not handling the keep-alive header properly), uHttpSharp library code fails to close the socket, this results in open sockets stuck in close_wait state.
Am new to C# not sure how to add this time out.

  {
    try
    {
        await InitializeStream();

        while (_client.Connected)
        {
            // TODO : Configuration.
            var limitedStream = new NotFlushingStream(new LimitedStream(_stream));

            var request = await _requestProvider.Provide(new MyStreamReader(limitedStream)).ConfigureAwait(false);

            if (request != null)
            {
                UpdateLastOperationTime();

                var context = new HttpContext(request, _client.RemoteEndPoint);

                Logger.InfoFormat("{1} : Got request {0}", request.Uri, _client.RemoteEndPoint);


                await _requestHandler(context).ConfigureAwait(false);

                if (context.Response != null)
                {
                    var streamWriter = new StreamWriter(limitedStream) { AutoFlush = false };
                    streamWriter.NewLine = "\r\n";
                    await WriteResponse(context, streamWriter).ConfigureAwait(false);

                     //v----- connections seem to be stuck here, resulting in piling up of  sockets in close_wait state
                    await limitedStream.ExplicitFlushAsync().ConfigureAwait(false); 

                    if (!request.Headers.KeepAliveConnection() || context.Response.CloseConnection)
                    {
                        _client.Close();
                    }
                }

                UpdateLastOperationTime();
            }
            else
            {
                _client.Close();
            }
        }
    }
    catch (Exception e)
    {
        // Hate people who make bad calls.
        Logger.WarnException(string.Format("Error while serving : {0}", _remoteEndPoint), e);
        _client.Close();
    }

    Logger.InfoFormat("Lost Client {0}", _remoteEndPoint);
}

Activity

  1. TahirAwan121 commented on Jun 18, 2019

    @TahirAwan121

    private async void Process()
    {
    try
    {
    await InitializeStream();

                while (_client.Connected)
                {
                    // TODO : Configuration.
                    var limitedStream = new NotFlushingStream(new LimitedStream(_stream));
    
                    //TimeOut Code start
    
                    TimeSpan timeout = TimeSpan.FromSeconds(10);
    
                    Logger.InfoFormat("{1} : Timeout set to {0} seconds", timeout.Seconds.ToString(), DateTime.Now.ToString());
                    IHttpRequest request = null;
    

    //v----- connections seem to be stuck here
    //var request = await _requestProvider.Provide(new MyStreamReader(limitedStream)).ConfigureAwait(false);

                    using (var timeoutCancellationTokenSource = new CancellationTokenSource())
                    {
                        
                        var task = _requestProvider.Provide(new MyStreamReader(limitedStream));
    
                        Logger.InfoFormat("{1} : Fetching 'task' with the task.Id.ToString() = {0}", task.Id.ToString(), DateTime.Now.ToString());
    
                        var completedTask = await Task.WhenAny(task, Task.Delay(timeout, timeoutCancellationTokenSource.Token)); 
    
                        Logger.InfoFormat("{1} : Fetched 'completedTask' with the completedTask.Id.ToString() = {0}", completedTask.Id.ToString(), DateTime.Now.ToString());
    
                        if (completedTask == task)
                        {
                            timeoutCancellationTokenSource.Cancel();
                            request = task.GetAwaiter().GetResult();
                            
                        }
                        else
                        {
                            Logger.InfoFormat("{0} : TimeOut Exception occured.", DateTime.Now.ToString());
                            
                            throw new TimeoutException();
                        }
                    }
                   
    
                    if (request != null)
                    {
                        UpdateLastOperationTime();
    
                        var context = new HttpContext(request, _client.RemoteEndPoint);
    
                        Logger.InfoFormat("{1} : Got request {0}", request.Uri, _client.RemoteEndPoint);
    
    
                        await _requestHandler(context).ConfigureAwait(false);
    
                        if (context.Response != null)
                        {
                            var streamWriter = new StreamWriter(limitedStream) { AutoFlush = false };
                            streamWriter.NewLine = "\r\n";
                            await WriteResponse(context, streamWriter).ConfigureAwait(false);
                            await limitedStream.ExplicitFlushAsync().ConfigureAwait(false);
    
                            if (!request.Headers.KeepAliveConnection() || context.Response.CloseConnection)
                            {
                                
                                _client.Close();
                            }
                        }
    
                        UpdateLastOperationTime();
                    }
                    else
                    {
                        
                        _client.Close();
                    }
                }
            }
            catch (Exception e)
            {
                // Hate people who make bad calls.
                Logger.WarnException(string.Format("Error while serving : {0}", _remoteEndPoint), e);
                _client.Close();
            }
    
            Logger.InfoFormat("Lost Client {0}", _remoteEndPoint);
        }
    

    We were also facing the same issue where the logic got stuck at the 'request' line indicated above. So we introduced a timeout value of 10 seconds to get out but it has caused another exception as given below:

    [2] [Error] [Default]: An unobserved task exception has occurred in the application: Exception: System.IO.IOException: Unable to read data from the transport connection: A blocking operation was interrupted by a call to WSACancelBlockingCall. ---> System.Net.Sockets.SocketException: A blocking operation was interrupted by a call to WSACancelBlockingCall

    Does anyone has a solution for this please?

    Kind Regards

  2. smaudet commented on Feb 25, 2024

    @smaudet

    Not a solution but I think this library is poorly designed, trying close http/https ports is a struggle/impossible. Dispose etc. is simply missing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions