Using TCP/IP KeepAlive in C#

R

Roy Chastain

I have been trying to make NetSocket.SetSocketOption work for TCP/IP KeepAlive

I have tried the following code

public virtual void SetKeepAlive (ulong keepalive_time, ulong keepalive_interval)
{
int bytes_per_long = 32 / 8;
byte [] keep_alive = new byte[3*bytes_per_long];
ulong [] input_params = new ulong[3];
int i1;
int bits_per_byte = 8;

if (keepalive_time == 0 || keepalive_interval == 0)
input_params[0] = 0;
else
input_params[0] = 1;
input_params[1] = keepalive_time;
input_params[2] = keepalive_interval;
for (i1=0; i1<input_params.Length; i1++)
{
keep_alive[i1*bytes_per_long+3] = (byte)(input_params[i1] >> ((bytes_per_long - 1) * bits_per_byte) & 0xff);
keep_alive[i1*bytes_per_long+2] = (byte)(input_params[i1] >> ((bytes_per_long - 2) * bits_per_byte) & 0xff);
keep_alive[i1*bytes_per_long+1] = (byte)(input_params[i1] >> ((bytes_per_long - 3) * bits_per_byte) & 0xff);
keep_alive[i1*bytes_per_long+0] = (byte)(input_params[i1] >> ((bytes_per_long - 4) * bits_per_byte) & 0xff);
}
LogTrace.Trace(this,"Keep Alive Bits: {0}",ByteArrayFormater.HexDump(keep_alive));
NetSocket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.KeepAlive,keep_alive);
} /* method AsyncSocket SetKeepAlive */


The result is not error, no exception and no keepalive in the expected time frame.
I am passing both times in mill-seconds. The Trace that I have shows 12 bytes in the form of
01 00 00 00 10 27 00 00 98 3a 00 00 when called as SetKeepAlive(10000,15000);

I am not really sure if I need to put the bytes in this order or not. If working directly with the Winsock API, the keepalive
option uses a structure of 3 ULONGS with a 1 in the first one, the time in the 2nd one and the retry time (interval in this code)
in the third one.

Any help on this would be appreciated.
 
G

Goran Sliskovic

Roy said:
I have been trying to make NetSocket.SetSocketOption work for TCP/IP KeepAlive

I have tried the following code

public virtual void SetKeepAlive (ulong keepalive_time, ulong keepalive_interval)
{
int bytes_per_long = 32 / 8;
byte [] keep_alive = new byte[3*bytes_per_long]; ....

LogTrace.Trace(this,"Keep Alive Bits: {0}",ByteArrayFormater.HexDump(keep_alive));
NetSocket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.keep alive,keep_alive);
} /* method AsyncSocket SetKeepAlive */


The result is not error, no exception and no keepalive in the expected time frame.
I am passing both times in mill-seconds. The Trace that I have shows 12 bytes in the form of
01 00 00 00 10 27 00 00 98 3a 00 00 when called as SetKeepAlive(10000,15000);
....

I'm not sure that .NET implementation expects timeouts. I think it
expects bool (enable/disable). Maybe you cold PInvoke WSAIoctl...

Regards,
Goran
 
A

appzguy

I have done this in the past

socket.SetSocketOption(SocketOptionLevel.Tcp,SocketOptionName.KeepAlive,1);

and then I tweaked the registry entries to set keep-alive intervals
The reg keys are located at
[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters]

KeepAliveTime = milliseconds
Specifies the connection idle time in milliseconds before TCP will
begin sending keepalives, if keepalives are enabled on a connection.
The default is 2 hours (7,200,000).

KeepAliveInterval = 32-bit number
Specifies the time in milliseconds between retransmissions of
keepalives, once the KeepAliveTime has expired. Once KeepAliveTime has
expired, keepalives are sent every KeepAliveInterval milliseconds until
a response is received, up to a maximum of MaxDataRetries before the
connection is terminated. The default is 1 second (1000).


Roy said:
I have been trying to make NetSocket.SetSocketOption work for TCP/IP KeepAlive

I have tried the following code

public virtual void SetKeepAlive (ulong keepalive_time, ulong keepalive_interval)
{
int bytes_per_long = 32 / 8;
byte [] keep_alive = new byte[3*bytes_per_long];
ulong [] input_params = new ulong[3];
int i1;
int bits_per_byte = 8;

if (keepalive_time == 0 || keepalive_interval == 0)
input_params[0] = 0;
else
input_params[0] = 1;
input_params[1] = keepalive_time;
input_params[2] = keepalive_interval;
for (i1=0; i1<input_params.Length; i1++)
{
keep_alive[i1*bytes_per_long+3] = (byte)(input_params[i1] >> ((bytes_per_long - 1) * bits_per_byte) & 0xff);
keep_alive[i1*bytes_per_long+2] = (byte)(input_params[i1] >> ((bytes_per_long - 2) * bits_per_byte) & 0xff);
keep_alive[i1*bytes_per_long+1] = (byte)(input_params[i1] >> ((bytes_per_long - 3) * bits_per_byte) & 0xff);
keep_alive[i1*bytes_per_long+0] = (byte)(input_params[i1] >> ((bytes_per_long - 4) * bits_per_byte) & 0xff);
}
LogTrace.Trace(this,"Keep Alive Bits: {0}",ByteArrayFormater.HexDump(keep_alive));
NetSocket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.KeepAlive,keep_alive);
} /* method AsyncSocket SetKeepAlive */


The result is not error, no exception and no keepalive in the expected time frame.
I am passing both times in mill-seconds. The Trace that I have shows 12 bytes in the form of
01 00 00 00 10 27 00 00 98 3a 00 00 when called as SetKeepAlive(10000,15000);

I am not really sure if I need to put the bytes in this order or not. If working directly with the Winsock API, the keepalive
option uses a structure of 3 ULONGS with a 1 in the first one, the time in the 2nd one and the retry time (interval in this code)
in the third one.

Any help on this would be appreciated.
 
R

Roy Chastain

Thanks for you comments. Your solution explains the note in the doc that says that KeepAlives can be enabled with the form of the
function that uses the int as the 3rd parameter.

I might go that way for a bit, but in the long run I want more control than the registry offers. (I want different sockets to
have different values.)


I have done this in the past

socket.SetSocketOption(SocketOptionLevel.Tcp,SocketOptionName.KeepAlive,1);

and then I tweaked the registry entries to set keep-alive intervals
The reg keys are located at
[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters]

KeepAliveTime = milliseconds
Specifies the connection idle time in milliseconds before TCP will
begin sending keepalives, if keepalives are enabled on a connection.
The default is 2 hours (7,200,000).

KeepAliveInterval = 32-bit number
Specifies the time in milliseconds between retransmissions of
keepalives, once the KeepAliveTime has expired. Once KeepAliveTime has
expired, keepalives are sent every KeepAliveInterval milliseconds until
a response is received, up to a maximum of MaxDataRetries before the
connection is terminated. The default is 1 second (1000).


Roy said:
I have been trying to make NetSocket.SetSocketOption work for TCP/IP KeepAlive

I have tried the following code

public virtual void SetKeepAlive (ulong keepalive_time, ulong keepalive_interval)
{
int bytes_per_long = 32 / 8;
byte [] keep_alive = new byte[3*bytes_per_long];
ulong [] input_params = new ulong[3];
int i1;
int bits_per_byte = 8;

if (keepalive_time == 0 || keepalive_interval == 0)
input_params[0] = 0;
else
input_params[0] = 1;
input_params[1] = keepalive_time;
input_params[2] = keepalive_interval;
for (i1=0; i1<input_params.Length; i1++)
{
keep_alive[i1*bytes_per_long+3] = (byte)(input_params[i1] >> ((bytes_per_long - 1) * bits_per_byte) & 0xff);
keep_alive[i1*bytes_per_long+2] = (byte)(input_params[i1] >> ((bytes_per_long - 2) * bits_per_byte) & 0xff);
keep_alive[i1*bytes_per_long+1] = (byte)(input_params[i1] >> ((bytes_per_long - 3) * bits_per_byte) & 0xff);
keep_alive[i1*bytes_per_long+0] = (byte)(input_params[i1] >> ((bytes_per_long - 4) * bits_per_byte) & 0xff);
}
LogTrace.Trace(this,"Keep Alive Bits: {0}",ByteArrayFormater.HexDump(keep_alive));
NetSocket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.KeepAlive,keep_alive);
} /* method AsyncSocket SetKeepAlive */


The result is not error, no exception and no keepalive in the expected time frame.
I am passing both times in mill-seconds. The Trace that I have shows 12 bytes in the form of
01 00 00 00 10 27 00 00 98 3a 00 00 when called as SetKeepAlive(10000,15000);

I am not really sure if I need to put the bytes in this order or not. If working directly with the Winsock API, the keepalive
option uses a structure of 3 ULONGS with a 1 in the first one, the time in the 2nd one and the retry time (interval in this code)
in the third one.

Any help on this would be appreciated.
 
G

Gary Chang[MSFT]

Hi Roy,

In Windows 2000 and later Windows operating systems, we can control the
per-connection setting of keep-alive option, keepalive time, and keepalive
interval. Basically, this could be done by the PSDK API WSAIoctl(...) with
the SIO_KEEPALIVE_VALS as its IOControlCode:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/win
sock/wsaioctl_2.asp


The .NET framework also provides a method to access that low level
functionality: Socket.IOControl. I found a newsgroup thread which discuss
the usage on using the SIO_KEEPALIVE_VALS:

Socket.IOControl and SIO_KEEPALIVE_VALS
http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/brow
se_thread/thread/a71b3a2912595769/48c72a728cc51a57?lnk=st&q=&rnum=1&hl=en#48
c72a728cc51a57

Socket.IOControl Method (IOControlCode, Byte[], Byte[])
http://msdn2.microsoft.com/en-us/library/8a3744sh.aspx


I hope the above information helps, if you have any issues or concerns
please let me know. I will be happy to be of further assistance.

Thanks!

Best regards,

Gary Chang
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
R

Roy Chastain

Okay, the message thread you pointed me is a discussion of Socket.IOControl that gets fairly messy in the 1.1 environment. I am
in the 1.1 environment..

My attempt uses Socket.SetSocketOption and eventually these 2 methods should end up running through the same code in WinSock. I
know how to set a KeepAlive in C++ using WinSock. I have been doing that for years.

The question that still remains using IOControl is, "What is the proper packing of the ULONGS into the byte array?"

Given the SIO_KEEPALIVE_VALS structure of
struct tcp_keepalive {
u_long onoff;
u_long keepalivetime;
u_long keepaliveinterval;
};

onoff will be 1
keepalivetime will be 10000
keepaliveinterval will be 15000

Should the byte array be packed like this
01 00 00 00 10 27 00 00 98 3a 00 00
or should they be packed like this
00 00 00 01 00 00 27 10 00 00 3a 98
or possibly some other pattern I have not figured out?
AND is this pattern machine dependent. (Intel vs. rest of the world?)

Also as an aside, do we expect SetSocketOption to work once the bytes are in the correct order or do I have to change to
IOControl? If we do not expect tSetSocketOption to work, then KeepAlive should be removed from the SocketOptionName enumeration.


Hi Roy,

In Windows 2000 and later Windows operating systems, we can control the
per-connection setting of keep-alive option, keepalive time, and keepalive
interval. Basically, this could be done by the PSDK API WSAIoctl(...) with
the SIO_KEEPALIVE_VALS as its IOControlCode:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/win
sock/wsaioctl_2.asp


The .NET framework also provides a method to access that low level
functionality: Socket.IOControl. I found a newsgroup thread which discuss
the usage on using the SIO_KEEPALIVE_VALS:

Socket.IOControl and SIO_KEEPALIVE_VALS
http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/brow
se_thread/thread/a71b3a2912595769/48c72a728cc51a57?lnk=st&q=&rnum=1&hl=en#48
c72a728cc51a57

Socket.IOControl Method (IOControlCode, Byte[], Byte[])
http://msdn2.microsoft.com/en-us/library/8a3744sh.aspx


I hope the above information helps, if you have any issues or concerns
please let me know. I will be happy to be of further assistance.

Thanks!

Best regards,

Gary Chang
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Gary Chang[MSFT]

Hi Roy,
Okay, the message thread you pointed me is a discussion
of Socket.IOControl that gets fairly messy in the 1.1
environment. I am in the 1.1 environment..

Just as that thread discussed, you can define the enum code manually:

SIO_KEEPALIVE_VALS is:
-1744830460 (or 0x98000004)

Should the byte array be packed like this
01 00 00 00 10 27 00 00 98 3a 00 00

The above is exactly the raw byte array layout of the struct tcp_keepalive
in little endian machine, you can take this one in most Windows platforms.
But it would be better to write some little code to test the machine's
endian type, then transfer the proper byte array due to the machine's
endian type.
Also as an aside, do we expect SetSocketOption to work once
the bytes are in the correct order or do I have to change to
IOControl?

The .NET framework's SetSocketOption method hasn't provided much control to
low level socket settings. Its socket option for the keep alive feature
could only be zero or non-zero value, it is used to enable or disable the
KeepAlive feature. So pass a byte array would not work. I suggest you take
the IOControl approach.

Thanks for your understanding.

Best regards,

Gary Chang
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 

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