runtime: Binding with ReuseAddress not working with UdpClient on Linux

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:

...
MultiCastClient = new UdpClient();

MultiCastClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
var EndPoint = new IPEndPoint(IPAddress.Any, _listenPort);
MultiCastClient.JoinMulticastGroup(IPAddress.Parse(multicastAddress));

MultiCastClient.Client.Bind(EndPoint); // <--- this is where the bind exception happens.

try
{
	MultiCastClient.BeginReceive(RecieveCallBack, null);
}
...

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 CLR aspnetcore-runtime-2.1 (all on Debian 9) I am getting a bind exception:

Application startup exception: System.Net.Sockets.SocketException (98): Address already in use
   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 UDPNMEAMessageReciever.UdpMessageProcessor.Start()
...

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

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 40 (19 by maintainers)

Most upvoted comments

@karelz - I was able to copy over our parts of the UdpClient issue, but not the ones from the others having he same problem.

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);

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…

you’re the one who edited the roadmap document

Fair point. It is so long time ago that I forgot 😃, sorry!

You should be able to work around the issue as described here: https://github.com/dotnet/corefx/issues/32027#issuecomment-418082355

@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 setsockopt(s.Handle.ToInt32(), 1, 2, &value, sizeof(int)); you should be able to unblock yourself. Please give it a try, an confirm that resolves the issue.

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);