C# .Net 10054 UDP Exception? Cause, fix? [duplicate] - c#

I need to obtain UDP datagram from Asynchronous Socket Server but an exception occurred in my application :
Problem appear there :
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
The full source code:
class Program
{
static void Main(string[] args)
{
const int PORT = 30485;
IPAddress IP;
IPAddress.TryParse("92.56.23.87", out IP);
// This constructor arbitrarily assigns the local port number.
UdpClient udpClient = new UdpClient(PORT);
Socket receiveSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
try
{
udpClient.Connect("92.56.23.87", PORT);
if (udpClient.Client.Connected)
Console.WriteLine("Connected.");
// Sends a message to the host to which you have connected.
Byte[] sendBytes = Encoding.ASCII.GetBytes("CONNECT");
udpClient.Send(sendBytes, sendBytes.Length);
//IPEndPoint object will allow us to read datagrams sent from any source.
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IP, PORT);
// Blocks until a message returns on this socket from a remote host.
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.ASCII.GetString(receiveBytes);
// Uses the IPEndPoint object to determine which of these two hosts responded.
Console.WriteLine("This is the message you received " + returnData.ToString());
Console.WriteLine("This message was sent from " + RemoteIpEndPoint.Address.ToString() + " on their port number " + RemoteIpEndPoint.Port.ToString());
udpClient.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
Exception:
Connected.
System.Net.Sockets.SocketException (0x80004005): An existing connection
was forcibly closed by the remote host at System.Net.Sockets.Socket.ReceiveFrom(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags, EndPoint& remoteEP) at ystem.Net.Sockets.UdpClient.Receive(IPEndPoint& remoteEP) at ConsoleApplication7.Program.Main(String[] args) in c:\users\user\documents\visual studio 2010\Projects\ConsoleApplication7\ConsoleApplication7\Program.cs
What can be the problem?
To provide more information, i bought the private socks connection on this page: http://rapidsocks.com/
this services give me a list of IP and port who in really is not a proxy .. just a connection that give me a proxyIP:proxyPort from a pool on server in response...
How to get that answer with proxyIP:proxyPort from the server?

In UDP land, one way this can occur is when you send a UDP packet to a host, and the remote host doesn't have a listener on that port, and bounces an ICMP host unreachable message in response.
In plain English, what this exception tells you that no process is listening on the far-end on that port.
Update: You should be able to avoid that behavior with the following code:
var udpClient = new UdpClient();
uint IOC_IN = 0x80000000;
uint IOC_VENDOR = 0x18000000;
uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
udpClient.Client.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
Microsoft Article 263823 said this on the subject: [hard to find as of 2019]
SYMPTOMS
In Windows 2000, a User Datagram Protocol (UDP) program may
not work and may generate a WSAECONNRESET response.
CAUSE
If sending a datagram using the sendto function results in an
"ICMP port unreachable" response and the select function is set for
readfds, the program returns 1 and the subsequent call to the recvfrom
function does not work with a WSAECONNRESET (10054) error response. In
Microsoft Windows NT 4.0, this situation causes the select function to
block or time out.
RESOLUTION
A new sockets IOCTL called "SIO_UDP_CONNRESET" has been
introduced in Windows 2000. When this IOCTL is used, the program must
be rewritten specifically for Windows 2000 to obtain the original
Windows NT 4.0 behavior. Windows NT 4.0, Microsoft Windows 95, and
Microsoft Windows 98 have no support for this new IOCTL. In addition
to rewriting your application, you will need the hotfix referenced
further down in this article.

This really is a generic error message that could mean anything. Time to get the low level network traffic sniffers to filter what is actually going wrong. Adding extra error handling try catch blocks on the server with decent logging is always a great place to start.

Related

Connect to a remote endpoint using UDP Socket in Xamarin (C#) only works when activating a VPN

I have a UDP Socket connection working between devices with local IPs (192.168.x.x), that I want to switch to a connection with an external server, with the following configuration:
Create socket
private Socket _socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
private const int bufSize = 4096 * 4;
private State state = new State();
private EndPoint epFrom = new IPEndPoint(IPAddress.Any, 0);
private AsyncCallback recv = null;
private static int PORT = 27000;
Openning device as a server to listen through the socket
_socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.ReuseAddress, true);
_socket.Bind(new IPEndPoint(IPAddress.Any, port));
Receive(); // Function to receive datagrams through the socket, irrelevant to this issue
Connect socket to remote endpoint
// {address:port} of an external server
_socket.Connect(new IPEndPoint(IPAddress.Parse(address), port));
Send data to socket
_socket.BeginSend(data, 0, data.Length, SocketFlags.None, (ar) =>
{
try
{
_socket.EndSend(ar);
}
catch (Exception ex)
{
Console.WriteLine("[UDP] Error Send: " + ex.ToString());
}
}, state);
The code above works fine for local IP addresses, the problem came when trying to use as a remote ip endpoint a public IP of a remote server.
The datagram seemed to be sent but it never arrived to the server. I tried to connect the phone to a VPN and the local IP changed from a 192.168.x.x to a 10.0.x.x, and then the connection to the external server worked.
Therefore, connection with an external IP only worked when the device's IP was a private IP of class A, but it didn't work with a class C range (https://www.meridianoutpost.com/resources/articles/IP-classes.php).
I want to find a solution to be able to connect to external IP address without having to connect a third party VPN software.
If someone has the same question, I have already solved it.
To access external IPs with local class C IPs and no VPN you should do UDP hole punching instead of trying to establish a connection.
Erase the .Connect() and the .Bind() methods, and, instead of using BeginSend/EndSend, use the SendTo or SendToAsync methods with the server's public IP as the endpoint destination.
Additionally, I recommend changing:
SocketOptionName.ReuseAddress
to:
SocketOptionName.PacketInformation

Why does sending via a UdpClient cause subsequent receiving to fail?

I'm trying to create a UDP server which can send messages to all the clients that send messages to it. The real situation is a little more complex, but it's simplest to imagine it as a chat server: everyone who has sent a message before receives all the messages that are sent by other clients.
All of this is done via UdpClient, in separate processes. (All network connections are within the same system though, so I don't think the unreliability of UDP is an issue here.)
The server code is a loop like this (full code later):
var udpClient = new UdpClient(9001);
while (true)
{
var packet = await udpClient.ReceiveAsync();
// Send to clients who've previously sent messages here
}
The client code is simple too - again, this is slightly abbreviated, but full code later:
var client = new UdpClient();
client.Connect("127.0.0.1", 9001);
await client.SendAsync(Encoding.UTF8.GetBytes("Hello"));
await Task.Delay(TimeSpan.FromSeconds(15));
await client.SendAsync(Encoding.UTF8.GetBytes("Goodbye"));
client.Close();
This all works fine until one of the clients closes its UdpClient (or the process exits).
The next time another client sends a message, the server tries to propagate that to the now-closed original client. The SendAsync call for that doesn't fail - but then when the server loops back to ReceiveAsync, that fails with an exception, and I haven't found a way to recover.
If I never send a message to the client that's disconnected, I never see the problem. Based on that I've also created a "fails immediately" repro which just sends to an endpoint assumed not to be listening, and then tries to receive. This fails with the same exception.
Exception:
System.Net.Sockets.SocketException (10054): An existing connection was forcibly closed by the remote host.
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.CreateException(SocketError error, Boolean forAsyncThrow)
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ReceiveFromAsync(Socket socket, CancellationToken cancellationToken)
at System.Net.Sockets.Socket.ReceiveFromAsync(Memory`1 buffer, SocketFlags socketFlags, EndPoint remoteEndPoint, CancellationToken cancellationToken)
at System.Net.Sockets.Socket.ReceiveFromAsync(ArraySegment`1 buffer, SocketFlags socketFlags, EndPoint remoteEndPoint)
at System.Net.Sockets.UdpClient.ReceiveAsync()
at Program.<Main>$(String[] args) in [...]
Environment:
Windows 11, x64
.NET 6
Is this expected behaviour? Am I using UdpClient incorrectly on the server side? I'm fine with clients not receiving messages after they've closed their UdpClient (that's to be expected), and in the "full" application I'll tidy up my internal state to keep track of "active" clients (who have sent packets recently) but I don't want one client closing a UdpClient to bring down the whole server. Run the server in one console, and the client in another. Once the client has finished once, run it again (so that it tries to send to the now-defunct original client).
The default .NET 6 console app project template is fine for all projects.
Repro code
The simplest example comes first - but if you want to run a server and client, they're shown afterwards.
Deliberately broken server (fails immediately)
Based on the assumption that it really is the sending that's causing the problem, this is easy to reproduce in just a few lines:
using System.Net;
using System.Net.Sockets;
var badEndpoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12346);
var udpClient = new UdpClient(12345);
await udpClient.SendAsync(new byte[10], badEndpoint);
await udpClient.ReceiveAsync();
Server
using System.Net;
using System.Net.Sockets;
using System.Text;
var udpClient = new UdpClient(9001);
var endpoints = new HashSet<IPEndPoint>();
try
{
while (true)
{
Log($"{DateTime.UtcNow:HH:mm:ss.fff}: Waiting to receive packet");
var packet = await udpClient.ReceiveAsync();
var buffer = packet.Buffer;
var clientEndpoint = packet.RemoteEndPoint;
endpoints.Add(clientEndpoint);
Log($"Received {buffer.Length} bytes from {clientEndpoint}: {Encoding.UTF8.GetString(buffer)}");
foreach (var otherEndpoint in endpoints)
{
if (!otherEndpoint.Equals(clientEndpoint))
{
await udpClient.SendAsync(buffer, otherEndpoint);
}
}
}
}
catch (Exception e)
{
Log($"Failed: {e}");
}
void Log(string message) =>
Console.WriteLine($"{DateTime.UtcNow:HH:mm:ss.fff}: {message}");
Client
(I previously had a loop actually receiving the packets sent by the server, but that doesn't seem to make any difference, so I've removed it for simplicity.)
using System.Net.Sockets;
using System.Text;
Guid clientId = Guid.NewGuid();
var client = new UdpClient();
Log("Connecting UdpClient");
client.Connect("127.0.0.1", 9001);
await client.SendAsync(Encoding.UTF8.GetBytes($"Hello from {clientId}"));
await Task.Delay(TimeSpan.FromSeconds(15));
await client.SendAsync(Encoding.UTF8.GetBytes($"Goodbye from {clientId}"));
client.Close();
Log("UdpClient closed");
void Log(string message) =>
Console.WriteLine($"{DateTime.UtcNow:HH:mm:ss.fff}: {message}");
As you may be aware, if a host receives a packet for a UDP port that is not currently bound, it may send back an ICMP "Port Unreachable" message. Whether or not it does this is dependent on the firewall, private/public settings, etc. On localhost, however, it will pretty much always send this packet back.
In your server code, you are calling SendAsync to old clients, which prompts these "port unreachable" messages.
Now, on Windows (and only on Windows), by default, a received ICMP Port Unreachable message will close the UDP socket that sent it; hence, the next time you try to receive on the socket, it will throw an exception because the socket has been closed by the OS.
Obviously, this causes a headache in the multi-client, single-server socket set-up you have here, but luckily there is a fix:
You need to utilise the not-often-required SIO_UDP_CONNRESET Winsock control code, which turns off this built-in behaviour of automatically closing the socket.
I don't believe this ioctl code is available in the dotnet IoControlCodes type, but you can define it yourself. If you put the following code at the top of your server repro, the error no longer gets raised.
const uint IOC_IN = 0x80000000U;
const uint IOC_VENDOR = 0x18000000U;
/// <summary>
/// Controls whether UDP PORT_UNREACHABLE messages are reported.
/// </summary>
const int SIO_UDP_CONNRESET = unchecked((int)(IOC_IN | IOC_VENDOR | 12));
var udpClient = new UdpClient(9001);
udpClient.Client.IOControl(SIO_UDP_CONNRESET, new byte[] { 0x00 }, null);
Note that this ioctl code is only supported on Windows (XP and later), not on Linux, since it is provided by the Winsock extensions. Of course, since the described behavior is only the default behavior on Windows, this omission is not a major loss. If you are attempting to create a cross-platform library, you should cordon this off as Windows-specific code.
As a result of other peoples work inhere, I made a little udpSocket creation code, that will handle the if windows/if not logic incapsulated:
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
public static class UdpSocketUtils
{
public static Socket CreateUdpSocket(IPEndPoint localEndpoint)
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.ReuseAddress, true);
socket.Bind(localEndpoint);
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
// Due to this issue: https://stackoverflow.com/questions/74327225/why-does-sending-via-a-udpclient-cause-subsequent-receiving-to-fail
// .. the following needs to be done on windows
const uint IOC_IN = 0x80000000U;
const uint IOC_VENDOR = 0x18000000U;
const int SIO_UDP_CONNRESET = unchecked((int)(IOC_IN | IOC_VENDOR | 12));
socket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0x00 }, null);
}
return socket;
}
}

.NET UDP Data Reception

I have a simple UDP listener that I am trying to collect datagrams from. My datagrams can be in one of two data formats. With the first data format, I am receiving data in my program as expected. With the second, there is absolutely no indication that data is ever received from my program, even though I can verify that the UDP data is passing onto the the network interface via Wireshark. I thought that maybe these were malformed UDP packets that Windows was rejecting but Wireshark does label them as UDP. My code is below:
static void Main(string[] args)
{
Thread thdUdpServer = new Thread(new ThreadStart(serverThread));
thdUdpServer.Start();
}
static void serverThread()
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.Bind(new IPEndPoint(new IPAddress(0), 2000));
while (true)
{
byte[] responseData = new byte[128];
socket.Receive(responseData);
string returnData = Encoding.ASCII.GetString(responseData);
Console.WriteLine(DateTime.Now + " " + returnData);
}
The missing packets are all 29 byte datagrams that look something like this (translated to ASCII).
#01RdFFFF...?...... ........F
Why would Wireshark indicate their presence but .NET not seem to see them?
If the bytes contain non-printable ASCII characters, you may not see them on the Console.
There's something missing in your code. It should be throwing a socket exception when calling ReceiveFrom (at least according to MSDN, haven't tried your code.)
You should bind your socket to the address:port you want to listen on (or use 0.0.0.0 as the address to listen on any local address):
socket.Bind(new IPEndPoint(new IPAddress(0), 2000);
The EndPoint in ReceiveFrom is not the listening port for the server. It's the address you want to receive packets from. You can use an Endpoint of 0.0.0.0:0 to receive from any host.
After returning from the method the Endpoint will be filled with the address of the host that sent the packet (client).
You can use Receive instead of ReceiveFrom if you don't care about the client end point.
Likely your client is not sending packets from 192.168.1.100:2000, and that is why you are not receiving them; thought why you're not getting an exception when calling ReceiveFrom is beyond me.
Also:
There is no need to call Convert.ToInt32 in:
new IPEndPoint(IPAddress.Parse("192.168.1.100"), Convert.ToInt32(2000));
2000 is already an int.

How do I implement Traceroute using UDP?

Apparently ICMP isn't the only way to create a Traceroute. This and this answer indicates it's possible to send a UDP packet (or any other) with a low TTL and wait for the ICMP message.
How would I go about implementing this in C#? System.IO.Sockets? The TCP objects? Anyone know of an easy/best way?
Update 1:
The following code seems to correctly throw an exception when the TTL is hit. How do I extract information from the returned UDP Packet?
How do I know that the UDP packet I'm receiving is intended for me (and not some other application on my host?)
public void PingUDPAsync(IPAddress _destination, short ttl)
{
// This constructor arbitrarily assigns the local port number.
UdpClient udpClient = new UdpClient(21000);
udpClient.Ttl = ttl;
// udpClient.DontFragment = true;
try
{
udpClient.Connect(_destination, 21000);
// Sends a message to the host to which you have connected.
Byte[] sendBytes = Encoding.ASCII.GetBytes("Is anybody there?");
udpClient.Send(sendBytes, sendBytes.Length);
//IPEndPoint object will allow us to read datagrams sent from any source.
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
// Blocks until a message returns on this socket from a remote host.
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.ASCII.GetString(receiveBytes);
// Uses the IPEndPoint object to determine which of these two hosts responded.
Console.WriteLine("This is the message you received " +
returnData.ToString());
Console.WriteLine("This message was sent from " +
RemoteIpEndPoint.Address.ToString() +
" on their port number " +
RemoteIpEndPoint.Port.ToString());
udpClient.Close();
}
catch (SocketException socketException)
{
Console.WriteLine(socketException.ToString());
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
Yes, System.Net.Sockets should provide you all the primitive objects you would need to send/receive UDP/TCP packets. Plenty of documentation and samples online, the two articles you included in your question are very interesting and a good starting point :)
https://learningnetwork.cisco.com/thread/87497
You can check out the answer here that goes into detail on Cisco's UPD traceroute implementation. It is rather comprehensive and can easily adapted to target a specific UDP port. You do not get a UDP packet back from the target. Rather, you get an ICMP reply to indicate the traffic was not received. The UDP packet that you originate has a random response port number included and your host tracks what ports are used by what applications. When the ICMP response is sent back, it is sent to the host IP and the response port included in the UDP header. Your host will then see the port and know it is bound to your application. It then delivers the packet to your application.

An existing connection was forcibly closed by the remote host

I need to obtain UDP datagram from Asynchronous Socket Server but an exception occurred in my application :
Problem appear there :
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
The full source code:
class Program
{
static void Main(string[] args)
{
const int PORT = 30485;
IPAddress IP;
IPAddress.TryParse("92.56.23.87", out IP);
// This constructor arbitrarily assigns the local port number.
UdpClient udpClient = new UdpClient(PORT);
Socket receiveSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
try
{
udpClient.Connect("92.56.23.87", PORT);
if (udpClient.Client.Connected)
Console.WriteLine("Connected.");
// Sends a message to the host to which you have connected.
Byte[] sendBytes = Encoding.ASCII.GetBytes("CONNECT");
udpClient.Send(sendBytes, sendBytes.Length);
//IPEndPoint object will allow us to read datagrams sent from any source.
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IP, PORT);
// Blocks until a message returns on this socket from a remote host.
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.ASCII.GetString(receiveBytes);
// Uses the IPEndPoint object to determine which of these two hosts responded.
Console.WriteLine("This is the message you received " + returnData.ToString());
Console.WriteLine("This message was sent from " + RemoteIpEndPoint.Address.ToString() + " on their port number " + RemoteIpEndPoint.Port.ToString());
udpClient.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
Exception:
Connected.
System.Net.Sockets.SocketException (0x80004005): An existing connection
was forcibly closed by the remote host at System.Net.Sockets.Socket.ReceiveFrom(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags, EndPoint& remoteEP) at ystem.Net.Sockets.UdpClient.Receive(IPEndPoint& remoteEP) at ConsoleApplication7.Program.Main(String[] args) in c:\users\user\documents\visual studio 2010\Projects\ConsoleApplication7\ConsoleApplication7\Program.cs
What can be the problem?
To provide more information, i bought the private socks connection on this page: http://rapidsocks.com/
this services give me a list of IP and port who in really is not a proxy .. just a connection that give me a proxyIP:proxyPort from a pool on server in response...
How to get that answer with proxyIP:proxyPort from the server?
In UDP land, one way this can occur is when you send a UDP packet to a host, and the remote host doesn't have a listener on that port, and bounces an ICMP host unreachable message in response.
In plain English, what this exception tells you that no process is listening on the far-end on that port.
Update: You should be able to avoid that behavior with the following code:
var udpClient = new UdpClient();
uint IOC_IN = 0x80000000;
uint IOC_VENDOR = 0x18000000;
uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
udpClient.Client.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
Microsoft Article 263823 said this on the subject: [hard to find as of 2019]
SYMPTOMS
In Windows 2000, a User Datagram Protocol (UDP) program may
not work and may generate a WSAECONNRESET response.
CAUSE
If sending a datagram using the sendto function results in an
"ICMP port unreachable" response and the select function is set for
readfds, the program returns 1 and the subsequent call to the recvfrom
function does not work with a WSAECONNRESET (10054) error response. In
Microsoft Windows NT 4.0, this situation causes the select function to
block or time out.
RESOLUTION
A new sockets IOCTL called "SIO_UDP_CONNRESET" has been
introduced in Windows 2000. When this IOCTL is used, the program must
be rewritten specifically for Windows 2000 to obtain the original
Windows NT 4.0 behavior. Windows NT 4.0, Microsoft Windows 95, and
Microsoft Windows 98 have no support for this new IOCTL. In addition
to rewriting your application, you will need the hotfix referenced
further down in this article.
This really is a generic error message that could mean anything. Time to get the low level network traffic sniffers to filter what is actually going wrong. Adding extra error handling try catch blocks on the server with decent logging is always a great place to start.

Categories

Resources