CoAPnet icon indicating copy to clipboard operation
CoAPnet copied to clipboard

CoapClient.Dispose blocking for some reason

Open n-develop opened this issue 3 years ago • 9 comments

For some reason, that I wasn't able to find yet, the Dispose function of the client is somehow blocked / won't exit. It doesn't matter If I run the code in a unit test or a console application. I'm using a using statement, just like in the sample code. The code runs fine. I implemented a couple of functions to work with the Ikea Gateway.

But as soon as my code hits the end of the using statement, it will just run forever. I also tried the example code from the wiki and I have the same behavior. So that could serve as my example code for the issue. But if I could provide any more details that can help you fix that, please let me know.

I'm using a MacBook Pro with Big Sur 11.2.3 and .NET 5 (5.0.102).

n-develop avatar Mar 27 '21 22:03 n-develop

That sounds strange to me. Please try with netstandard because I assume the following line may be the problem: https://github.com/chkr1011/CoAPnet/blob/master/Source/CoAPnet/Transport/TcpCoapTransportLayer.cs#L35

The tcp client is not set and not closed with the ? operator. I assume that also .NET 5.0 must be added to the compiler pragma because it should use the same code path as netstandard I guess.

chkr1011 avatar Mar 27 '21 22:03 chkr1011

I'm not sure about the netstandard part. The nuget package is available for .NetStandard 2.0 and .NET Framework 4.5.2. So it's compiled for these two targets, correct?

With .NET5, the netstandard target is used already. Would it help, if I post the stack at the end of the program?

Main Thread:

ManualResetEventSlim.Wait()
Task.SpinThenBlockingWait()
Task.InternalWaitCore()
TaskAwaiter.HandleNonSuccessAndDebuggerNotification()
TaskAwaiter.GetResult()
Program.<Main>()

Other threads:

SpinWait.SpinOnceCore()
SpinWait.SpinOnce()
SafeSocketHandle.CloseAsIs()
Socket.Dispose()
Socket.Dispose()
UdpTransport.Dispose()
UdpTransport.Close()
DtlsCoapTransportLayer.<ReceiveAsync>b__13_0()
CancellationToken.<>c.<.cctor>b__26_0()
CancellationTokenSource.CallbackNode.<>c.<ExecuteCallback>b__9_0()
ExecutionContext.RunInternal() [4]
CancellationTokenSource.CallbackNode.ExecuteCallback()
CancellationTokenSource.ExecuteCallbackHandlers()
CancellationTokenSource.NotifyCancellation()
CancellationTokenSource.Cancel()
CoapClient.Dispose()
async Class1.Method1()
AsyncTaskMethodBuilder<VoidTaskResult>.AsyncStateMachineBox<__Canon>.ExecutionContextCallback()
ExecutionContext.RunInternal() [3]
AsyncTaskMethodBuilder<VoidTaskResult>.AsyncStateMachineBox<Class1.<Method1>d__0>.MoveNext()
AsyncTaskMethodBuilder<VoidTaskResult>.AsyncStateMachineBox<__Canon>.MoveNext()
AwaitTaskContinuation.RunOrScheduleAction() [3]
Task.RunContinuations() [3]
Task.FinishContinuations() [3]
Task<__Canon>.TrySetResult() [3]
AsyncTaskMethodBuilder<__Canon>.SetExistingTaskResult() [3]
AsyncTaskMethodBuilder<CoapResponse>.SetResult()
CoapClient.<RequestAsync>d__12.MoveNext()
AsyncTaskMethodBuilder<CoapResponse>.AsyncStateMachineBox<CoapClient.<RequestAsync>d__12>.ExecutionContextCallback()
ExecutionContext.RunInternal() [2]
AsyncTaskMethodBuilder<CoapResponse>.AsyncStateMachineBox<CoapClient.<RequestAsync>d__12>.MoveNext()
AsyncTaskMethodBuilder<CoapResponse>.AsyncStateMachineBox<CoapClient.<RequestAsync>d__12>.MoveNext()
AwaitTaskContinuation.RunOrScheduleAction() [2]
Task.RunContinuations() [2]
Task.FinishContinuations() [2]
Task<__Canon>.TrySetResult() [2]
AsyncTaskMethodBuilder<__Canon>.SetExistingTaskResult() [2]
AsyncTaskMethodBuilder<CoapMessage>.SetResult() [2]
CoapClient.<RequestAsync>d__15.MoveNext()
AsyncTaskMethodBuilder<CoapMessage>.AsyncStateMachineBox<CoapClient.<RequestAsync>d__15>.ExecutionContextCallback()
ExecutionContext.RunInternal() [1]
AsyncTaskMethodBuilder<CoapMessage>.AsyncStateMachineBox<CoapClient.<RequestAsync>d__15>.MoveNext()
AsyncTaskMethodBuilder<CoapMessage>.AsyncStateMachineBox<CoapClient.<RequestAsync>d__15>.MoveNext()
AwaitTaskContinuation.RunOrScheduleAction() [1]
Task.RunContinuations() [1]
Task.FinishContinuations() [1]
Task<__Canon>.TrySetResult() [1]
AsyncTaskMethodBuilder<__Canon>.SetExistingTaskResult() [1]
AsyncTaskMethodBuilder<CoapMessage>.SetResult() [1]
CoapMessageAwaiter.<WaitOneAsync>d__4.MoveNext()
AsyncTaskMethodBuilder<CoapMessage>.AsyncStateMachineBox<CoapMessageAwaiter.<WaitOneAsync>d__4>.ExecutionContextCallback()
ExecutionContext.RunFromThreadPoolDispatchLoop()
AsyncTaskMethodBuilder<CoapMessage>.AsyncStateMachineBox<CoapMessageAwaiter.<WaitOneAsync>d__4>.MoveNext()
AsyncTaskMethodBuilder<CoapMessage>.AsyncStateMachineBox<CoapMessageAwaiter.<WaitOneAsync>d__4>.ExecuteFromThreadPool()
ThreadPoolWorkQueue.Dispatch()
_ThreadPoolWaitCallback.PerformWaitCallback()
[Native to Managed Transition]
async .()

SocketPal.SysReceive()
SocketPal.TryCompleteReceiveFrom()
SocketAsyncContext.ReceiveFrom()
SocketPal.ReceiveFrom()
Socket.ReceiveFrom()
UdpTransport.Receive()
DtlsRecordLayer.ReceiveRecord()
DtlsRecordLayer.Receive()
DtlsTransport.Receive()
DtlsCoapTransportLayer.ReceiveAsync()
CoapTransportLayerAdapter.<ReceiveAsync>d__5.MoveNext()
AsyncMethodBuilderCore.Start<CoAPnet.Transport.CoapTransportLayerAdapter.<ReceiveAsync>d__5>()
AsyncTaskMethodBuilder<int>.Start<CoAPnet.Transport.CoapTransportLayerAdapter.<ReceiveAsync>d__5>()
CoapTransportLayerAdapter.ReceiveAsync()
LowLevelCoapClient.<ReceiveAsync>d__9.MoveNext()
AsyncMethodBuilderCore.Start<CoAPnet.LowLevelClient.LowLevelCoapClient.<ReceiveAsync>d__9>()
AsyncTaskMethodBuilder<CoapMessage>.Start<CoAPnet.LowLevelClient.LowLevelCoapClient.<ReceiveAsync>d__9>()
LowLevelCoapClient.ReceiveAsync()
CoapClient.<ReceiveMessages>d__17.MoveNext()
AsyncMethodBuilderCore.Start<CoAPnet.Client.CoapClient.<ReceiveMessages>d__17>()
AsyncTaskMethodBuilder.Start<CoAPnet.Client.CoapClient.<ReceiveMessages>d__17>()
CoapClient.ReceiveMessages()
CoapClient.<ConnectAsync>b__11_0()
Task<Task>.InnerInvoke()
Task.<>c.<.cctor>b__277_0()
ExecutionContext.RunInternal() [2]
Task.ExecuteWithThreadLocal()
Task.ExecuteEntryUnsafe()
ThreadPoolTaskScheduler.<>c.<.cctor>b__10_0()
ThreadHelper.ThreadStart_Context()
ExecutionContext.RunInternal() [1]
ThreadHelper.ThreadStart()
[Native to Managed Transition]

n-develop avatar Mar 27 '21 23:03 n-develop

You maybe need to upgrade bouncycastle. I saw that newer versions got some DTLS fixes with infinite loops etc. https://www.bouncycastle.org/csharp/#RELEASENOTES189

chkr1011 avatar Mar 28 '21 12:03 chkr1011

I updated the BouncyCastle package, but that did not fix it. I forked your project. Maybe I can take a look at the problem. When I Iook at the second stack trace, it looks like the call to "UdpTransport.Close()" that was initialized by the CancellationToken leads to some kind of lock.

SpinWait.SpinOnceCore()
SpinWait.SpinOnce()
SafeSocketHandle.CloseAsIs()
Socket.Dispose()
Socket.Dispose()
UdpTransport.Dispose()
UdpTransport.Close()    <-- 3) The CancellationToken has a registered callback to call Close() on the UdpTransport
DtlsCoapTransportLayer.<ReceiveAsync>b__13_0()
CancellationToken.<>c.<.cctor>b__26_0()
CancellationTokenSource.CallbackNode.<>c.<ExecuteCallback>b__9_0()
ExecutionContext.RunInternal() [4]
CancellationTokenSource.CallbackNode.ExecuteCallback()
CancellationTokenSource.ExecuteCallbackHandlers()
CancellationTokenSource.NotifyCancellation()
CancellationTokenSource.Cancel()   <--  2) ... and that call the cancel method
CoapClient.Dispose()   <-- 1) I think this is triggered by the end of the using statement
...

n-develop avatar Mar 28 '21 14:03 n-develop

But having a lock in these classes cannot be fixed in this library I guess. Could you please try to call socket.Shutdown() before disposing the socket? What happens when you completely remove the call to socket.Dispose().

chkr1011 avatar Mar 28 '21 16:03 chkr1011

Shutdown throws an exception, that the socket isn't open. When I remove the _socket?.Dispose() in UdpTransport.cs, it seems to work fine.

n-develop avatar Mar 30 '21 11:03 n-develop

Maybe it is related to an issue like this one: https://github.com/dotnet/runtime/issues/42686

chkr1011 avatar Mar 30 '21 12:03 chkr1011

That looks similar, indeed.

n-develop avatar Mar 31 '21 08:03 n-develop

@n-develop Is this issue not yet fixed with a new .NET version?

chkr1011 avatar Jun 18 '22 09:06 chkr1011