Home All Groups Group Topic Archive Search About

UDP Comms and Connection Reset Problem

Author
21 Jun 2006 1:43 PM
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?

Author
21 Jun 2006 6:40 PM
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
Author
21 Jun 2006 9:51 PM
Jonas Hei
Markus Stoeger wrote:
> 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)
Author
22 Jun 2006 5:48 PM
Jonas Hei
Jonas Hei wrote:
> 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);
Author
22 Jun 2006 7:39 PM
Markus Stoeger
Jonas Hei wrote:
Show quote
> 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

AddThis Social Bookmark Button