Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

crash during discovery #13

Closed
ispysoftware opened this issue May 24, 2020 · 3 comments · Fixed by #15
Closed

crash during discovery #13

ispysoftware opened this issue May 24, 2020 · 3 comments · Fixed by #15

Comments

@ispysoftware
Copy link

Hey @vmartos thanks for your library! I'm getting an exception on using Discover

try
            {
                var onvifDiscovery = new OnvifDiscovery.Discovery();
                var devices = (await onvifDiscovery.Discover(5)).ToList();
                lock (_lock)
                {
                    _discoveredDevices = devices;
                }
            }
            catch(Exception ex)
            {
                Logger.LogException(ex, "ONVIF Discovery");
            }           
  • it's always throwing an exception after the timeout finishes with "An existing connection was forcibly closed by the remote host".

_discoveredDevices is never populated. This is a net standard 2.0 project.

Stack trace:

" at System.Net.Sockets.Socket.DoBeginReceiveFrom(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags, EndPoint endPointSnapshot, SocketAddress socketAddress, OverlappedAsyncResult asyncResult)
at System.Net.Sockets.Socket.BeginReceiveFrom(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags, EndPoint& remoteEP, AsyncCallback callback, Object state)
at System.Net.Sockets.UdpClient.BeginReceive(AsyncCallback requestCallback, Object state)
at System.Threading.Tasks.TaskFactory1.FromAsyncImpl(Func3 beginMethod, Func2 endFunction, Action1 endAction, Object state, TaskCreationOptions creationOptions)
at System.Net.Sockets.UdpClient.ReceiveAsync()
at OnvifDiscovery.Client.OnvifUdpClient.d__3.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at OnvifDiscovery.Common.ExtensionMethods.d__01.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at OnvifDiscovery.Common.ExtensionMethods.<WithCancellation>d__01.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at OnvifDiscovery.Discovery.d__4.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at OnvifDiscovery.Discovery.d__3.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at CoreLogic.Onvif.Discovery.d__6.MoveNext() in D:\Projects\agent-service\CoreLogic2\Onvif\Discovery.cs:line 51"

@ispysoftware
Copy link
Author

... needed to add

catch(Exception ex) {
// Other exception
}

to line 91 of Discovery.cs

@vicmaeg
Copy link
Owner

vicmaeg commented May 28, 2020

Hello @ispysoftware, Thanks for reporting the issue. Can I know in which OS and target runtime is running the .netstandard library? I could not reproduce it. Did you reproduce it constantly? or some of the times? just to know if some sort of a race condition between the udpClient.Close() and udpClient.ReceiveAsync(). Also I need the Exception Type is it a ObjectDisposedException or SocketException

You need to add the following to make it working?

} finally {
  try {
    client.Close ();
  } catch {
    // socket close failed
  }
}

or the following?

} catch (OperationCanceledException) {
// Either the user canceled the action or the timeout has fired
} catch (Exception) {
// ReceiveAsync failed
} finally {
  client.Close ();
}

But yeah this can happen because UdpClient.ReceiveAsync does not have a CancellationToken, so what I do is the following:

                /// <summary>
		/// Used to provide cancellation possibility to any Async Methods returning a Task
		/// </summary>
		internal static async Task<T> WithCancellation<T> (this Task<T> task, CancellationToken cancellationToken)
		{
			var tcs = new TaskCompletionSource<bool> ();
			using (cancellationToken.Register (s => ((TaskCompletionSource<bool>)s).TrySetResult (true), tcs)) {
				if (task != await Task.WhenAny (task, tcs.Task)) {
					throw new OperationCanceledException (cancellationToken);
				}
			}
			return await task;
		}

This just returns when the initial task (ReceiveAsync) finishes or the cancellationToken is cancelled, but in fact the ReceiveAsync is still executing...

I will investigate if there is a better solution to manage the cancellation of the opened Udp socket.

@ispysoftware
Copy link
Author

it was working for ages but then one of my cameras started malfunctioning and closing the request which triggered the exception in the library so reproducing it is hard unless you build a virtual client that just closes the response. Until I rebooted the camera it was happening on every run of the discovery code.

Running on Windows 10, .Net Framework 4.7

adding the catch-all case after OperationCanceledException "fixed" it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants