Yortw / RSSDP

Really Simple Service Discovery Protocol - a 100% .Net implementation of the SSDP protocol for publishing custom/basic devices, and discovering all device types on a network.

Home Page:http://yortw.github.io/RSSDP/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Calling SearchAsync produce random ObjectDisposedException as unhandled

Rambalac opened this issue · comments

Stack

>	System.Net.Sockets.dll!System.Net.Sockets.Socket.EndReceiveFrom(System.IAsyncResult asyncResult, ref System.Net.EndPoint endPoint)	Unknown
 	System.Net.Sockets.dll!System.Net.Sockets.SocketTaskExtensions.ReceiveFromAsync.AnonymousMethod__8_1(System.IAsyncResult asyncResult)	Unknown
 	System.Private.CoreLib.ni.dll!System.Threading.Tasks.TaskFactory<System.Net.Sockets.SocketReceiveFromResult>.FromAsyncCoreLogic(System.IAsyncResult iar, System.Func<System.IAsyncResult, System.Net.Sockets.SocketReceiveFromResult> endFunction, System.Action<System.IAsyncResult> endAction, System.Threading.Tasks.Task<System.Net.Sockets.SocketReceiveFromResult> promise, bool requiresSynchronization)	Unknown
 	System.Private.CoreLib.ni.dll!System.Threading.Tasks.TaskFactory<System.Net.Sockets.SocketReceiveFromResult>.FromAsyncImpl.AnonymousMethod__0(System.IAsyncResult iar)	Unknown
 	System.Net.Sockets.dll!System.Net.LazyAsyncResult.Complete(System.IntPtr userToken)	Unknown
 	System.Net.Sockets.dll!System.Net.ContextAwareResult.CompleteCallback()	Unknown
 	System.Net.Sockets.dll!System.Net.ContextAwareResult.Complete.AnonymousMethod__15_0(object s)	Unknown
 	System.Private.CoreLib.ni.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state)	Unknown
 	System.Net.Sockets.dll!System.Net.ContextAwareResult.Complete(System.IntPtr userToken)	Unknown
 	System.Net.Sockets.dll!System.Net.LazyAsyncResult.ProtectedInvokeCallback(object result, System.IntPtr userToken)	Unknown
 	System.Net.Sockets.dll!System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(uint errorCode, uint numBytes, System.Threading.NativeOverlapped* nativeOverlapped)	Unknown
 	System.Threading.Overlapped.dll!System.Threading.Win32ThreadPoolNativeOverlapped.OnExecutionContextCallback(object state)	Unknown
 	System.Private.CoreLib.ni.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state)	Unknown
 	System.Threading.Overlapped.dll!System.Threading.Win32ThreadPoolNativeOverlapped.CompleteWithCallback(uint errorCode, uint bytesWritten, System.Threading.Win32ThreadPoolNativeOverlapped* overlapped)	Unknown
 	System.Threading.Overlapped.dll!System.Threading.ThreadPoolBoundHandle.OnNativeIOCompleted(System.IntPtr instance, System.IntPtr context, System.IntPtr overlappedPtr, uint ioResult, System.UIntPtr numberOfBytesTransferred, System.IntPtr ioPtr)	Unknown

I'm using RSSDP for Windows 10 UWP app.

My init code

foreach (var host in confirmedHosts)
            {
                var deviceLocator =
                    new SsdpDeviceLocator(new SsdpCommunicationsServer(new SocketFactory(host.CanonicalName)))
                    {
                        NotificationFilter = "urn:schemas-upnp-org:device:MediaServer:1"
                    };
                deviceLocator.DeviceAvailable += DeviceLocator_DeviceAvailable;
                deviceLocator.StartListeningForNotifications();
                deviceLocators.Add(deviceLocator);
            }

And the call

try
            {
                foreach (var dev in deviceLocators)
                {
                    await dev.SearchAsync();
                }
            }
            catch (Exception e)
            {
                Log.Debug(e);
            }

And handler

        private async void DeviceLocator_DeviceAvailable(object sender, DeviceAvailableEventArgs arg)
        {
            try
            {
                ....
            }
            catch (Exception e)
            {
                Debug.WriteLine(e);
                Log.Error(e);
            }
        }

Removing the call stops unhandled exceptions

I have my own UDP receiver code using DatagramSocket and it has no such problem.

Just was able to catch exception while closing my app

 	Rssdp.NetCore.dll!Rssdp.Infrastructure.SsdpCommunicationsServer.SendMessage(byte[] messageData, Rssdp.Infrastructure.UdpEndPoint destination)	Unknown
 	Rssdp.NetCore.dll!Rssdp.Infrastructure.SsdpDeviceLocatorBase.BroadcastDiscoverMessage(string serviceType, System.TimeSpan mxValue)	Unknown
 	Rssdp.NetCore.dll!Rssdp.Infrastructure.SsdpDeviceLocatorBase.SearchAsync(string searchTarget, System.TimeSpan searchWaitTime)	Unknown
 	System.Private.CoreLib.ni.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.__Canon>.Start<Rssdp.Infrastructure.SsdpDeviceLocatorBase.<SearchAsync>d__18>(ref Rssdp.Infrastructure.SsdpDeviceLocatorBase.<SearchAsync>d__18 stateMachine)	Unknown
 	Rssdp.NetCore.dll!Rssdp.Infrastructure.SsdpDeviceLocatorBase.SearchAsync(string searchTarget, System.TimeSpan searchWaitTime)	Unknown
 	Rssdp.NetCore.dll!Rssdp.Infrastructure.SsdpDeviceLocatorBase.SearchAsync()	Unknown

If this happens while closing the app, it's not exactly random as the title suggests.

You've started an async task that is sending messages, and then you close the app while the send is in progress. Closing the app disposes the socket, which causes the socket calls on the other thread to throw a disposed exception.

When I get time I'll update the search code to suppress that exception in the right circumstances, but really if you're going to allow closing your app while async jobs like this are in progress (in RSSDP or anything else) you should be prepared to handle the exceptions in you app code.

Interestingly you seem to have two different errors. In the case of the first one, the stack trace doesn't appear to show any of my code in it, so it seems to be an exception thrown in the UWP runtime. It also appears to be happening on an internal thread, again with none of my code in the call stack, so I'm not sure what I can do about that. I can't even catch and suppress the error, since I have no code at the top of the call stack in which to put the try. It appears the socket is in a listening state and is throwing the error if the socket gets closed/disposed, but it shouldn't (you obviously need to be able to close a socket in that state at some point). I'm not sure at this stage how I can avoid that. Interestingly I haven't seen this error myself, despite having two LOB UWP apps that use the library. I'm not sure why you see it and I don't. Does it happen consistently? Is it when you close the app?

The second exception it should be possible to handle.

Hi,
I am still unable to reproduce the first error mentioned. Do you have any answers to my questions? Can you provide a project that reliable reproduces the issue?
Thanks.

For the second error I've decided this is not a bug and I am not going to change the code at this time;

  1. Disposing the locator while a search is in progress is a potential bug (or bad design) in the client app. If I were to change the code so it did not throw (and returned either a partial or empty result set) then the other thread in the app may error in some other way that makes it harder to understand what the problem is. The ObjectDisposedException can be caught and handled/suppressed by the client app if it knows this isn't a problem (and it also then knows not to the use the result)

  2. There is actually a unit test in the library that checks that we throw ObjectDisposedException (instead of some other exception such as null reference etc) when this case happens. This serves as documentation that it is the expected behaviour.

  3. Changing this is a breaking change - there may be existing applications that rely on ObjectDisposedException being thrown in this case, and removing that may break those applications.

I suggest, for the second case, you catch and handle/suppress the exception in your own code and take whatever action is appropriate (probably doing nothing and allowing the thread to end).

The first exception raised is still something I would like to fix, but as mentioend previously, I cannot reproduce and cannot see how to fix.

Hi,
Any update or project to reproduce the first issue?
I have a couple of different UWP Win10 projects and haven't been able to reproduce, so any more info or a project that reproduces the issue (or steps to reproduce) would be useful.
Thanks.

Sorry, but I don't have statistic on that error anymore. I got it from app users and then I just added it to unhandled exception handler. I still get it sometimes on my local device but that's not so often. I tried to reproduce it that weeks but did not get it in debugger.

I think I may have fixed this in v3.5.3. I believe the stacktrace refers to a compiler generated method that is a lambda function used as part of a task continuation. I've added code/logic there to avoid disposed exception caused by the locator class itself being disposed, so I hope that will fix this. Since neither of us can reproduce at will, we can't really confirm either way so I'm going to close this issue. If the issue continues to occur after upgrading to 3.5.3, please let me know. Thanks.

Thanks.