-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Cannot create AF_VSOCK Sockets due to overly strict SocketPal #58327
Comments
Tagging subscribers to this area: @dotnet/ncl Issue DetailsDescriptionHello, Unix SocketPal prevents managed code from creating AF_VSOCK (and any other new and/or non-standard AF's). This is unfortunate, because at the managed level, everything is there to extend for new address families: You write your EndPoint-derived implementation properly, and then it gets serialized to a SocketAddress, and that gets passed down to In Linux, SocketPal needs to do some translations, likely because some of the basic values do not match between their original Windows constants and the standard Linux ones. In its current form, the code there bails out entirely if anything is unknown: runtime/src/libraries/Native/Unix/System.Native/pal_networking.c Lines 2461 to 2487 in cffaa78
My exact use case is for AF_VSOCK. In this specific case, I guess the simplest fix would be to add AF_VSOCK to RegressionNo, pal_networking.c blame looks old over there. WorkaroundPinvoke
|
For that we also need a managed
If understand it correctly, this is due to a condition check before we call runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs Lines 179 to 186 in e0e7bfc
I'm wondering what would happen if we just removed this criteria to unblock scenarios dealing with connected sockets of arbitrary address families? |
cc @shirhatti |
From a framework perspective I guess this makes the most sense, but I was hoping this issue could be handled 100% internally at the PAL level so that it is easier to pass. I can submit an API proposal in parallel. At that point, would it only be the AddressFamily entry, or would it be AddressFamily + EndPoint impl? And AF_VSOCK only, or AF_HYPERV as well? Note that AF_HYPERV is not a problem, unlike VSOCK, because on Windows it is possible to write a fully functional EndPoint implementation and AF_HYPERV works completely in managed. But providing the implementation would add convenience. What I mean by handling it internally at the PAL is that could it be changed so that unknown values flow through to the native calls instead of early-returning an error? Right now it strictly enforces well-known values to guard against invalid parameters and sizes, but the native call would already return an adequate error if it does not like the parameters.
Yes. My understanding of that code is that relaxing those conditions would work. |
In #28636 (dotnet/corefx#37315) we shipped a few new address families without EndPoint implementations so it's probably not necessary, meaning that the minimal API would just focus on unblocking users instead of delivering a full solution. /cc @wfurt
To me it sounds reasonable to file a shared proposal for these two. |
I did some work on Netlink and It was working for me - at least the small part I was using. Supporting completely new protocols blindly is not trivial. As you noticed there are fragments in the socket code making certain assumptions. Ability to create Socket from handle was added to solve also some other use cases. Creating Socket from RAW AddressFamily was discussed but rejected as it may have still have some other lingering issue. For one, it may still have issue not knowing if socket is or is not Connected. Existing code is guessing and perhaps that may be improved. Alternatively we may pass that information to the constructor. Can you share your code @fbrosseau primarily the endpoint, creation and example oof what is not working? |
In Linux? Windows PAL allows for arbitrary AFs, but not Linux.
Anything that touches the AddressFamily throws. I can share a full example of what would be a correct VSockEndPoint implementation, but basically every step is a blocker :) Note that these errors are generated by the Unix PAL itself, not the OS. The OS would accept these parameters happily. See the part of pal_networking.c that I linked in OP |
Yes, on Linux. Windows does not have Netlink. And this is not what I meant. I know casting number to AddressFamily will not work. It is about creating handle you self, creating Socket from it and using your EndPoint for Bind(). |
Ah sorry! Yes, well managed Socket.Bind/.Connect is a no-go due to the SocketAddress constructor throwing, and I do not think there is any possible way to implement EndPoint.Serialize without it. So that step too must be done through PInvoke. But then due to the defensive code in the Socket constructor that takes a handle, _rightEndPoint is never considered if the AF is not IPv4/IPv6/Unix. |
Take a look at #26416. It has example of managed
This should all work AFAIK. |
LLEndpoint uses |
Than look at runtime/src/libraries/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs Line 584 in ebc0f05
Original addition of Netlink was reverted (e.g. there is neither PAL nor enum) but that test can still dump routing table. runtime/src/libraries/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs Lines 519 to 520 in ebc0f05
Netlink is one example were even if we added |
Ah yes interesting, I didn't realize SocketAddress could be fuzzed into changing the AF byte, this goes against both the docs and the code comments, so I did not expect this to be a supported scenario. runtime/src/libraries/Common/src/System/Net/SocketAddress.cs Lines 55 to 59 in 9671726
Then yes if that's supported that works, that removes the need for quite a bit of PInvoke, except the initial |
It would be probably cleaner if you can use |
AFAIK VSock is mainstream enough now and it also supports "loopback" that does not require having any actual VM in the system, so this is probably a good testable candidate AF. |
Yah, you can argue that about |
That's true, but we already have similar address families (eg. AF_PACKET), so I don't see an issue adding more of them. We should just point out in the docs, that the given enum value is platform-specific. I think this is a good candidate to be a community-driven feature, my recommendation is still to
Independently, we should also evaluate if we can improve the support of using arbitrary AddressFamilies / ProtocolTypes through P/Invoke and custom endpoints. I think we can provide limited support for advanced users without adding new API-s or implementing high impact changes like the eliminating strict PAL "mappability" criterias entirely, by doing just 2 things:
|
Sure I could look into that.
Could the TryConvertAddressFamilyPalToPlatform condition be relaxed in SystemNative_Socket too? The code already does not do anything with the result other than passing it to |
You want to use We need some API addition that indicates whether the values are raw ones. These could be some overload that accepts ints, similar to
API could be something in this direction: const int AF_VSOCK = 40;
const int SOCK_STREAM = 1;
using var socket = new Socket(AF_VSOCK, SOCK_STREAM, 0, new MyVSockEndPoint()); |
I am not sure I can see the concrete problem - the already existing special-cases (Packet, CAN) already have synthetic values on purpose to not clash with anything standard. So that part is fine. Then, for the normal stuff (IPv4 etc), the values are universal. For the AF values that do differ between platforms (VSock and HyperV are examples), the OS would already tell if the values are good or bad.
First argument would be redundant with the endpoint argument since the AF value is already part of the EndPoint contract. I am also not sure if having an endpoint at |
@tmds API addition is a very deep rabbit hole, the scope seems to be much bigger here than with
|
There is no standard that specifies these values are the same cross-platform.
The problem that needs to be solved is distinguish raw values from defined enum values.
These enums have an
Yes, only specific operations require |
Sounds reasonable to me, but wondering if anyone would push back on that.
I think this is something we should be capable to support with the current API-s. ( |
If we don't add a constructor to const int AF_VSOCK = 40;
const int SOCK_STREAM = 1;
const int SOCK_CLOEXEC = 0x80000;
[DllImport("libc", SetLastError = true)]
public static extern int socket(int domain, int type, int protocol);
int fd = socket(AF_VSOCK, SOCK_STREAM | SOCK_CLOEXEC, 0); // TODO: handle fd == -1
using var socket = new Socket(new SafeSocketHandle((IntPtr)fd, true), new MyVSockEndPoint()); |
Which might be acceptable for advanced scenarios. Again, I'm not super optimistic about our ability finalizing API proposals around the socket area, mostly because it has lower priority in comparison to other hot topics. (See our backlog of stale suggestions). I may give it a try though :)
This would mean that the raw address family and socket/protocol type is settable, but not queryable. This is quite atypical for BCL API-s, and likely not what we want there, meaning that we need to expose properties which is where the rabbit hole begins ... Regarding the code sample in #58327 (comment): I meant the |
Triage: Similar to #58378 (comment) -- there may be dragons, let's find out more first. |
Triage: not critical for 7.0, pushing to future for now. |
I noticed this myself when implementing a |
This may be officially relaxed as part of #30797. I don't if it would be useful but it would provide ability to send/receive without need for |
In the SocketCAN usecase, the Is there any scope in that ticket for also making SocketCAN code for reference: https://github.com/crozone/SocketCanNet/blob/main/SocketCanNet/CanSocketEndPoint.cs |
there is no plan for |
Description
Hello,
Unix SocketPal prevents managed code from creating AF_VSOCK (and any other new and/or non-standard AF's). This is unfortunate, because at the managed level, everything is there to extend for new address families: You write your EndPoint-derived implementation properly, and then it gets serialized to a SocketAddress, and that gets passed down to
socket
for the platform, and everything works. That is the case for Windows, where dotnet does not attempt to do anything with the parameters - if WinSock is happy with it, it works.In Linux, SocketPal needs to do some translations, likely because some of the basic values do not match between their original Windows constants and the standard Linux ones. In its current form, the code there bails out entirely if anything is unknown:
runtime/src/libraries/Native/Unix/System.Native/pal_networking.c
Lines 2461 to 2487 in cffaa78
My exact use case is for AF_VSOCK. In this specific case, I guess the simplest fix would be to add AF_VSOCK to
TryConvertAddressFamilyPalToPlatform
. However, should Linux SocketPal allow for arbitrary unknown AFs, like Windows does? That's a larger change, and that can come with complications if the values keep diverging over time between Linux and Windows.Regression
No, pal_networking.c blame looks old over there.
Workaround
Pinvoke
socket()
,connect()
/bind()
/ ... (basically anything that deals with EndPoint classes), and thennew Socket(new SafeSocketHandle((IntPtr)sock, true));
to leverage the actual Socket/IO benefits provided by .net.This workaround has multiple drawbacks - the current managed code in Socket gets all confused and assumes that the socket has Connected=false, due to the code only handling IPv4/IPv6/Unix in the SafeHandle constructor. Having Connected=false prevents it from using NetworkStream, for example. Then, if a Stream interface is required, the workaround is to instead use a FileStream over the sockfd. This is really not ideal : )
@antonfirsov
The text was updated successfully, but these errors were encountered: