Search code examples
c#.net.net-3.5dispose

Exception: cannot access a closed Stream (WinXP only!)


I am trying this TFTP client for my application as Client. However, there is a bug somewhere when sometimes my program which is trying to read the stream throwing exception that the stream is already closed. After some digging in source code I found that in TftpTransfer.cs there is Dispose method, which sometimes called and then exception is thrown.

I can't find why sometimes Dispose method is called before I use the stream(after TFTP transfer is done) and how to address it.

Following is the code and exception occurs on setting position to 0.

        private static AutoResetEvent TransferFinishedEvent = new AutoResetEvent(false);
        ....
        var client = new TftpClient("192.168.0.1");
        var transfer = client.Download("00-02.conf");
        transfer.OnFinished += new TftpEventHandler(transfer_OnFinshed);
        transfer.OnError += new TftpErrorHandler(transfer_OnError);
        Stream stream = new MemoryStream();
        transfer.Start(stream);
        TransferFinishedEvent.WaitOne();
        stream.Position = 0;
        var sr = new StreamReader(stream);
        var myStr = sr.ReadToEnd();
        Console.WriteLine(myStr);
        ...
        static void transfer_OnError(ITftpTransfer transfer, TftpTransferError error)
        {
            Console.WriteLine("Transfer failed: " + error);
            TransferFinishedEvent.Set();
        }

        static void transfer_OnFinshed(ITftpTransfer transfer)
        {
            Console.WriteLine("Transfer succeeded.");
            TransferFinishedEvent.Set();
        }

UPD: Workaround which didn't work yet

        MemoryStream stream = new MemoryStream();
        var sr = new StreamReader(new MemoryStream(stream.GetBuffer()));
        transfer.Start(stream);
        TransferFinishedEvent.WaitOne();
        
        Console.WriteLine(sr.ReadToEnd());

sr is always pointing to end of stream and it's empty.

UPD2: One thing which maybe worth to mention. Exception cannot access a closed Stream happens only on Windows XP box (.NET 3.5 which I have to stick to). I have tried on Windows 7 and even though sometimes I see the stream inside framework disposed, I don't have exception. Again, on Windows XP exception happens randomly. Approximately every 3 calls to my app throwing exception.


Solution

  • The stream appears to be closed by design in the library when it gets to the end of the download.

    //Was that the last block of data?
    if (command.Bytes.Length < Context.BlockSize)
    {
        Context.RaiseOnFinished();
        Context.SetState(new Closed());
    }
    

    Where the Closed state just calls Dispose() on the instance of TftpTransfer (which in turn closes the stream).

    I'd argue that's maybe a bug in the library - it doesn't own the stream so it shouldn't be closing it but you're stuck with that for now.

    The simplest solution is to create a new memory stream to read the bytes captured like this::

    var sr = new StreamReader(new MemoryStream(stream.GetBuffer());