Discussion:
UDP Comms and Connection Reset Problem
(too old to reply)
Jonas Hei
2006-06-21 13:43:05 UTC
Permalink
Our application does UDP communications using the Socket class in
System.Net.Sockets.

The Socket.EndReceiveFrom() often throws a SocketException (ErrorCode:
10054, WSAECONNRESET, "An existing connection was forcibly closed by the
remote host").

This seems to be a common problem affecting a lot of people and it
appears that this happens due to 'ICMP Port unreachable' responses to
the UDP messages already sent out. KB263823
(http://support.microsoft.com/kb/263823/en-us) explains the problem.

Looking at the above KB I expect to get SocketExceptions with
WSAECONNRESET during Socket.EndReceiveFrom(). And they do happen often.

But sometimes I also get same exception during
Socket.BeginReceiveFrom(). Why?

What is the best way to fix this problem?

Should we be using Socket.IOControl() to set SIO_UDP_CONNRESET to false?
(Our application runs on Windows Server 2003)

Or should we be catching SocketExceptions and ignoring the WSAECONNRESET
errors?
Markus Stoeger
2006-06-21 18:40:18 UTC
Permalink
Jonas Hei wrote:

Hi Jonas,
Post by Jonas Hei
Looking at the above KB I expect to get SocketExceptions with
WSAECONNRESET during Socket.EndReceiveFrom(). And they do happen often.
But sometimes I also get same exception during
Socket.BeginReceiveFrom(). Why?
I had the same problem just a few weeks ago. And I hate it for throwing
in BeginReceiveFrom!! My whole code was full of try/catches because of that.
Post by Jonas Hei
What is the best way to fix this problem?
Since I found out about the IOControl call with SIO_UDP_CONNRESET the
problem is gone (no more silly exceptions that I don't care about with
UDP!). I've successfully used that on W2K and XP so far.

Simply disabling that behaviour should definitelly be cheaper than
catching exceptions -- catching wastes lots of cpu cycles.

hth,
Max
Jonas Hei
2006-06-21 21:51:54 UTC
Permalink
Post by Markus Stoeger
Since I found out about the IOControl call with SIO_UDP_CONNRESET the
problem is gone (no more silly exceptions that I don't care about with
UDP!). I've successfully used that on W2K and XP so far.
Max, thanks a lot for the solution.

By the way how did you set SIO_UDP_CONNRESET to FALSE?

I have tried doing as per Zupancic's suggestion
(http://blog.devstone.com/aaron/archive/2005/02/20.aspx):
// 0x9800000C == 2440136844 (uint) == -174483042 (int) == 0x9800000C
const int SIO_UDP_CONNRESET = -174483042;
byte[] inValue = new byte[] { 0, 0, 0, 0 }; // == false
byte[] outValue = new byte[] { 0, 0, 0, 0 }; // initialize to 0
_socket.IOControl(SIO_UDP_CONNRESET, inValue, outValue);

But it does not work for me - it throws a SocketException (An invalid
argument was supplied).

The code illustrated in http://thedotnet.com/nntp/8375/showpost.aspx
does not work for me either.

By the way I am currently on .NET1.1/VS2003.
Even if I had been on .NET2.0 I guess the new method
Socket.IOControl(IOControlCode, Byte[], Byte[]) wouldn't have helped
me...I couldn't find the equivalent for SIO_UDP_CONNRESET in
IOControlCode enum
(http://msdn2.microsoft.com/en-us/library/system.net.sockets.iocontrolcode.aspx)
Jonas Hei
2006-06-22 17:48:41 UTC
Permalink
Post by Jonas Hei
I have tried doing as per Zupancic's suggestion
// 0x9800000C == 2440136844 (uint) == -174483042 (int) == 0x9800000C
const int SIO_UDP_CONNRESET = -174483042;
byte[] inValue = new byte[] { 0, 0, 0, 0 }; // == false
byte[] outValue = new byte[] { 0, 0, 0, 0 }; // initialize to 0
_socket.IOControl(SIO_UDP_CONNRESET, inValue, outValue);
But it does not work for me - it throws a SocketException (An invalid
argument was supplied).
Zupancic was just telling us that it is kind of lame to copy and paste
code snippets from anywhere without giving them a serious thought first.

So after being lame for a few hours (give or take a few more hours), I
finally gave some thought to it and luckily managed to solve the problem:
instead of
// 0x9800000C == 2440136844 (uint) == -174483042 (int) == 0x9800000C
we need
// 0x9800000C == 2550136844 (uint) == -1744830452 (int) == 0x9800000C

so this snippet seems to work:

const int SIO_UDP_CONNRESET = -1744830452;
byte[] inValue = new byte[] { 0, 0, 0, 0 }; // == false
byte[] outValue = new byte[] { 0, 0, 0, 0 }; // initialize to 0
_socket.IOControl(SIO_UDP_CONNRESET, inValue, outValue);
Markus Stoeger
2006-06-22 19:39:25 UTC
Permalink
Post by Jonas Hei
Zupancic was just telling us that it is kind of lame to copy and paste
code snippets from anywhere without giving them a serious thought first.
So after being lame for a few hours (give or take a few more hours), I
instead of
// 0x9800000C == 2440136844 (uint) == -174483042 (int) == 0x9800000C
we need
// 0x9800000C == 2550136844 (uint) == -1744830452 (int) == 0x9800000C
const int SIO_UDP_CONNRESET = -1744830452;
byte[] inValue = new byte[] { 0, 0, 0, 0 }; // == false
byte[] outValue = new byte[] { 0, 0, 0, 0 }; // initialize to 0
_socket.IOControl(SIO_UDP_CONNRESET, inValue, outValue);
I used the following code... looks clean to me. I don't think it's
necessary to pass arrays of 4 bytes. 1 byte is enough. And the second
array can be null because we don't need the return values:

uint IOC_IN = 0x80000000;
uint IOC_VENDOR = 0x18000000;
uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;

s.IOControl((int)SIO_UDP_CONNRESET, new byte[] {Convert.ToByte(false)},
null);

Max

Loading...