-
Notifications
You must be signed in to change notification settings - Fork 4.5k
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
Binding with ReuseAddress not working with UdpClient on Linux #27274
Comments
This may be caused by changes in dotnet/corefx#24809. With 2.0 ReuseAddress did:
With 2.1 it does:
I'm trying to reproduce this, but I'm missing something. I can run two instances of this program concurrently: static void Main(string[] args)
{
UdpClient MultiCastClient = new UdpClient();
MultiCastClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
var EndPoint = new IPEndPoint(IPAddress.Any, 5000);
MultiCastClient.JoinMulticastGroup(IPAddress.Parse("239.0.0.1"));
Console.Read();
} |
@olijf does this happen with two instances of your own program? Or is another program also using the port? |
Hi Tom, |
I can reproduce this. The issue occurs when two applications each use a different option: one does using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
namespace console
{
class Program
{
static unsafe void Main(string[] args)
{
bool reuseAddr = args.Length > 0;
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
if (reuseAddr)
{
System.Console.WriteLine("reuse address");
int value = 1;
setsockopt(s.Handle.ToInt32(), 1, 2, &value, sizeof(int));
}
else
{
System.Console.WriteLine("reuse port");
s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
}
s.Bind(new IPEndPoint(IPAddress.Parse("0.0.0.0"), 5000));
Console.Read();
}
[DllImport("libc", SetLastError = true)]
private unsafe static extern int setsockopt(int socket, int level, int option_name, void* option_value, uint option_len);
}
} The fix will be to change back to changing both options for @davidsh you can assign this to me. |
Hi @tmds , |
@karelz when the PR is merged on master, will it become part of the 2.2 release? Can we consider this for 2.1? @olijf by adding the peudo code: UdpClient MultiCastClient = new UdpClient();
MultiCastClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
// set SO_REUSEADDR (https://github.com/dotnet/corefx/issues/32027)
int value = 1;
setsockopt(MultiCastClient.Client.Handle.ToInt32(), 1, 2, &value, sizeof(int));
}
[DllImport("libc", SetLastError = true)]
private unsafe static extern int setsockopt(int socket, int level, int option_name, void* option_value, uint option_len); |
@tmds Your workaround works fine in one scenario but in another one i'm still getting the bind exception. I'm still investigation why this happens. |
@olijf When setting both SO_REUSEADDR (via setsockopt) and SO_REUSEPORT (via SocketOptionName.ReuseAddress), I only got a bind exception when a previous socket was bound that didn't set any option. |
@tmds master flows into 3.0. 2.2 is almost-servicing bar. Can you sum up the impact of this problem? If it is wide-impact, or if there is not a good workaround, we could consider it for 2.2 or 2.1.x. |
Based on reviewing the PR in master, it seems to be rather rare corner case, right? Given that we have only 1 report so far, I recommend to NOT port it to 2.2/2.1.x, until we get more developers hitting the problem. |
Hi @karelz , imho I think this is actually a pretty big issue. Because you can not distinguish between |
@olijf the key question is: How common is such setup? |
@olijf have you found the reason for the exception? |
This issue is fixed by dotnet/corefx#32046 |
Closing as fixed in dotnet/corefx#32046 |
Copying over from dotnet/corefx#37044:
|
Repro Szenario for UDP Bug@karelz - you wrote:
and
Following up your chat with @LukePulverenti about backporting the fix to 2.2, I have created a reproduction scenario for you: https://github.com/softworkz/ReuseBug The solution contains a native Linux app and a netcore console app, multi-targeting netcore 2.0, 2.2 and 3.0 This demonstrates:
I hope this helps getting the fix backported to 2.2... Originally posted by @softworkz in https://github.com/dotnet/corefx/issues/37044#issuecomment-495592262 |
|
And still we're asking for it. It's a bug - not a "corner case".
Not quite. We're not the only ones referring to the UDP bug here. Originally posted by @softworkz in https://github.com/dotnet/corefx/issues/37044#issuecomment-495927124 |
@karelz - I was able to copy over our parts of the UdpClient issue, but not the ones from the others having he same problem. |
Thanks @softworkz! @softworkz I wonder if it would be acceptable for you to wait for 3.0 RC in July (see roadmap). If there are more customers hitting it, impacting their production, we could consider backporting to 2.1/2.2. |
We are only one customer but we do bring a lot of users across every OS and NAS device that we can deploy the runtime to. Right now this is creating enough troubleshooting for us that in order to save face we are passing this information onto users and saying that we'll just have to wait for an updated runtime. We would prefer to not have to start building our own fork of the runtime from source, but it looks like that's where we're going to be headed if nothing changes here. |
Once we discovered the problem we thought we could wait until March which was the original roadmap date for netcore 3.0. (funny: Luke just wrote about the same...) |
You should be able to work around the issue as described here: https://github.com/dotnet/corefx/issues/32027#issuecomment-418082355 |
Just to clarify @softworkz @LukePulverenti: Are you from the same company? @softworkz AFAIK, March was never original roadmap for .NET Core 3.0. Can you please try workaround from @tmds? Would that be acceptable until you are able to upgrade to 3.0? |
More 'for' than 'from', but yes.
Well, now I'm confused because you're the one who edited the roadmap document: Q1 2019 was the announced ship date from May 24, 2018 until Nov 6, 2018.
We'll try and report back, thanks. |
Fair point. It is so long time ago that I forgot :), sorry! |
Quick update: The workaround was successful in case of my repro scenario. We're currently adding this to a new beta and then I'll report back.. |
I'm experiencing a similar issue. <06/04/2019 10:03:23> Address already in use
<06/04/2019 10:03:23> at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, String callerName)
at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.Sockets.Socket.Bind(EndPoint localEP)
at Zeroconf.NetworkInterface.NetworkRequestAsync(Byte[] requestBytes, TimeSpan scanTime, Int32 retries, Int32 retryDelayMilliseconds, Action`2 onResponse, NetworkInterface adapter, CancellationToken cancellationToken) in D:\a\1\s\Zeroconf\NetworkInterface.cs:line 107
at Zeroconf.NetworkInterface.NetworkRequestAsync(Byte[] requestBytes, TimeSpan scanTime, Int32 retries, Int32 retryDelayMilliseconds, Action`2 onResponse, NetworkInterface adapter, CancellationToken cancellationToken) in D:\a\1\s\Zeroconf\NetworkInterface.cs:line 169
at Zeroconf.NetworkInterface.NetworkRequestAsync(Byte[] requestBytes, TimeSpan scanTime, Int32 retries, Int32 retryDelayMilliseconds, Action`2 onResponse, CancellationToken cancellationToken) in D:\a\1\s\Zeroconf\NetworkInterface.cs:line 34
at Zeroconf.ZeroconfResolver.ResolveInternal(ZeroconfOptions options, Action`2 callback, CancellationToken cancellationToken) in D:\a\1\s\Zeroconf\ZeroconfResolver.cs:line 79
at Zeroconf.ZeroconfResolver.ResolveAsync(ResolveOptions options, Action`1 callback, CancellationToken cancellationToken) in D:\a\1\s\Zeroconf\ZeroconfResolver.Async.cs:line 98
at Zeroconf.ZeroconfResolver.ResolveAsync(IEnumerable`1 protocols, TimeSpan scanTime, Int32 retries, Int32 retryDelayMilliseconds, Action`1 callback, CancellationToken cancellationToken) in D:\a\1\s\Zeroconf\ZeroconfResolver.Async.cs:line 69 When I look into the relevant ZeroConf code, I notice that using (var client = new UdpClient())
{
for (var i = 0; i < retries; i++)
{
try
{
var socket = client.Client;
if (socket.IsBound) continue;
socket.SetSocketOption(SocketOptionLevel.IP,
SocketOptionName.MulticastInterface,
IPAddress.HostToNetworkOrder(ifaceIndex));
client.ExclusiveAddressUse = false;
socket.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReuseAddress,
true);
socket.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout,
(int)scanTime.TotalMilliseconds);
client.ExclusiveAddressUse = false;
var localEp = new IPEndPoint(IPAddress.Any, 5353);
Debug.WriteLine($"Attempting to bind to {localEp} on adapter {adapter.Name}");
socket.Bind(localEp); (The exception is thrown on the |
Was this ever backported to 2.2/2.1? |
It was not. There are no plans to backport it. In generally, not all fixes get backported to previous releases. |
Check out the latest .NET Core 3.0 preview. It is suitable for 'go-live' scenarios: https://devblogs.microsoft.com/dotnet/announcing-net-core-3-0-preview-9/ |
@davidsh Thanks, was hoping to not have to use the workaround. I am writing a library, users could be on any version. |
@matthew798 Not sure if this can help you but I posted a hack that works, it was tested on .NET Core 2.1. It could be improved, see https://github.com/QTimort/bind-reuse-port |
@QTimort Thanks. I'll have a look! |
Alternatively, you can us the code from https://github.com/dotnet/corefx/issues/32027#issuecomment-417395637 if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
// set SO_REUSEADDR (https://github.com/dotnet/corefx/issues/32027)
int value = 1;
setsockopt(MultiCastClient.Client.Handle.ToInt32(), 1, 2, &value, sizeof(int));
}
[DllImport("libc", SetLastError = true)]
private unsafe static extern int setsockopt(int socket, int level, int option_name, void* option_value, uint option_len); |
We had the same problem and I can confirm that this has fixed it for us. |
I'm not sure this is related to this issue, so if need by, I'll start another. I have observed what I think is a discrepency in how .net core handles sockets compared to native (on linux, at least) I am talking about the case where two sockets are bound to the same endpoint, but only one is connected to a remote endpoint. I have an SO question on the subject, and it seems that the behaviour is "undefned", yet the code here works perfectly, and does exactly that. Specifically, the code I linked creates 2 sockets, one to listen for incoming dtls "connection" requests, and another for a connected client. Both of these sockets are bound to the same endpoint, and the second is connected to the client's endpoint. The result is that all traffic originating from the "connected" client is forwarded to the socket created specifically for them, and all other traffic is forwarded to the unconnected socket. I tried to replicate this behaviour in C# with no luck. As I mentioned, it seems that in this specific case, the behavior is undefined and the data seems to be forwarded to a socket at random. My code is as follows:
At this point, there is no way to guarantee that the client's dgrams will make it to Is this a bug in .net? I am using .net core 3.0, so I know that both SO_REUSEADDRESS and SO_REUSEPORT are being set. I'm not sure what I am missing... |
In the code you linked to: SO_REUSEPORT is not set on Linux: https://github.com/nplab/DTLS-Examples/blob/226f222e528858b3a8c5fa3326b0599d25d3ef1c/src/dtls_udp_echo.c#L652-L654 |
Yes you are correct. My code doesn't work in both dotnet core 2.2 (where SO_REUSEPORT is not set) and 3.0 (where it is). So it seems that SO_REUSEPORT has no effect on the result. The bottom line is that the behavior I described is achievable in native code, but there seems to be no way in dotnet. Ill open another issue. |
From @olijf on August 30, 2018 11:13
Binding multiple clients on Linux platform in dotnet framework 2.1 does not work as expected
I am binding to a socket with SO_REUSEADDR (
MultiCastClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
) but on Linux this gives me an address already in use exception.In dotnet core 2.0 this was working fine.
General
I have the following relevant piece of code:
I have a project targeting netcoreapp2.0
When I am running this with
dotnet-hosting-2.0.8
everything is fine. However when I am running this with the newer CLRaspnetcore-runtime-2.1
(all on Debian 9) I am getting a bind exception:I havent looked into it much further, but I would like to be able to use the newer CLR.
Thanks for helping me out here, I really appreciate your efforts.
Copied from original issue: dotnet/coreclr#19765
The text was updated successfully, but these errors were encountered: