在Linux上从.NET Core手动调用recvmsg不会返回

时间:2017-08-08 16:42:35

标签: c# linux sockets .net-core

我正在为.NET Core here编写一个DBus客户端。对于某些功能(例如systemd的抑制器锁定),需要通过Unix套接字连接接收文件描述符,并且需要recvmsg放在struct msghdr中的与控件相关的消息。 .NETs套接字API不允许我访问该函数(或抽象),因此我必须手动调用它。

导致我第一次recvmsg来电的代码的内容是here。当我针对net462编译并在我的Ubuntu 16.04盒子或Yocto发行版(也使用Mono)上通过Mono 5.0.1运行它时,一切都按预期工作。

当我针对netcoreapp1.1 / netstandard1.6对其进行编译并使用dotnet运行时,问题就开始了:recvmsg调用只是在第一次Hello调用时没有返回org.freedesktop.DBus

我可以看到dbus-monitor --system方法调用已离开我的应用程序,并且DBus发送了方法返回以及NameOwnerChangedNameAcquired信号。

几点说明:

  • 对于我在Ubuntu上的测试,我已将size_tiovec中的msghdr字段从int更改为long,实际上是64位(虽然它看起来像结构所需的对齐使它无论如何都可以工作)
  • 套接字上的实际ConnectAsync调用略有不同:对于net462,我从.NET Core 1.1复制了extension method
  • 要了解原生套接字句柄,我可以使用net462上的Handle属性,但可以使用netcoreapp1.1构建中的resort to reflecting the private field
  • 我还检查过.NET Core 2.0 preview2版本,其行为与.NET Core 1.1
  • 完全相同
  • 在套接字而不是Read上调用recvmsg可以正常工作,尽管Read内部只是映射到recvmsg
  • 我比较了Mono和.NET Core之间Socket上的公共属性没有明显的区别:访问ExclusiveAddressUse可以在Mono上运行,但是会抛出.NET Core。
  • 在接收线程开始工作之前,有一些身份验证代码here。这会从套接字读取一些基于TPL的内容。

我试图浏览CoreFX套接字代码,但由于涉及的复杂性,这并不是很有趣。

缺少什么链接?

1 个答案:

答案 0 :(得分:1)

有两个连续的问题。

首先,我的receive方法成功地吞下了一个异常,如果我已经运行了Connection的Dispose方法而不是CTRL + C,那么该异常就可见了。

System.TypeLoadException: Cannot marshal field 'control' of type 'msghdr': Unknown error.
   at System.StubHelpers.ValueClassMarshaler.ConvertToNative(IntPtr dst, IntPtr src, IntPtr pMT, CleanupWorkList& pCleanupWorkList)
   at Dbus.Connection.recvmsg(IntPtr sockfd, msghdr& buf, Int32 flags)
   at Dbus.Connection.receive()

所以recvmsg从未实际调用过。原因是control字段已键入int[]。我将其更改为int*并添加了另一个fixed

奇怪的是,Mono能够使用int[]字段封送此结构,并且.NET Core不是。

之后,实际调用recvmsg,但立即返回-1。不过,如果我只是Read使用.NET套接字,一切都运行正常。我选择直接通过libc API运行整个套接字处理,不再使用.NET Core Socket类型。现在,recvmsg按预期工作。我假设我的基于TPL的DBus授权让套接字有一个有效读取,我的接收方法正在执行第二次读取被阻止"但我还没有验证这个假设。 / p>