UDP Comms and Connection Reset Problem

J

Jonas Hei

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?
 
M

Markus Stoeger

Jonas Hei wrote:

Hi Jonas,
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.
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
 
J

Jonas Hei

Markus said:
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)
 
J

Jonas Hei

Jonas said:
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).

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

Markus Stoeger

Jonas said:
Jonas Hei wrote:
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);

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top