using System;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Net;
namespace NCindy.Util
{
public static class WinSock2Wrapper
{
#region constants
public const int SO_CONNECT_TIME = 0x700C;
public const int INT32_LENGTH = 4;
private static readonly byte [] KeepAliveOn
= BitConverter.GetBytes((uint)1);
private static readonly byte [] KeepAliveOff
= BitConverter.GetBytes((uint)0);
private static readonly int UintSize = Marshal.SizeOf(typeof(uint));
#endregion
#region pinvoke methods
[DllImport("ws2_32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int getsockopt(
IntPtr socketHandle,
int level,
int optname,
out int optval,
ref int optlen);
[DllImport("ws2_32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int WSAGetLastError();
#endregion
/// <summary>
/// Get the local IPEndpoint which would be used to route to the given remote IPEndpoint.
/// </summary>
/// <param name="sock"></param>
/// <param name="remoteEP"></param>
/// <returns></returns>
public static IPEndPoint QueryRoutingInterface(Socket sock,
IPEndPoint remoteEP)
{
LangHelper.CheckNullArgument("sock", sock);
LangHelper.CheckNullArgument("remoteEP", remoteEP);
SocketAddress sa = remoteEP.Serialize();
byte[] remoteAddrBytes = new byte[sa.Size];
for (int i = 0; i < sa.Size; i++)
{
remoteAddrBytes[i] = sa[i];
}
byte[] localAddrBytes = new byte[remoteAddrBytes.Length];
sock.IOControl(IOControlCode.RoutingInterfaceQuery,
remoteAddrBytes,
localAddrBytes);
for (int i = 0; i < sa.Size; i++)
{
sa[i] = localAddrBytes[i];
}
EndPoint ep = remoteEP.Create(sa);
return (IPEndPoint) ep;
}
/// <summary>
/// Get socket connection e
/// </summary>
/// <param name="sock"></param>
/// <returns></returns>
public static int GetConnectTime(Socket sock)
{
if (sock == null)
{
throw new ArgumentNullException();
}
int connTime;
int optlen = INT32_LENGTH;
int retVal = getsockopt(sock.Handle,
(int)SocketOptionLevel.Socket,
SO_CONNECT_TIME,
out connTime,
ref optlen);
if (retVal == 0) // getsockopt succeed.
{
return connTime;
}
int errorCode = WSAGetLastError();
throw new SocketException(errorCode);
}
public static void SetKeepAlive(Socket s, bool on, uint time, uint interval)
{
/* the native structure
struct tcp_keepalive {
ULONG onoff;
ULONG keepalivetime;
ULONG keepaliveinterval;
};
*/
// marshal the equivalent of the native structure into a byte array
byte[] inOptionValues = new byte[UintSize * 3];
System.Buffer.BlockCopy(
on ? KeepAliveOn : KeepAliveOff,
0,
inOptionValues,
0,
UintSize);
System.Buffer.BlockCopy(BitConverter.GetBytes(time),
0,
inOptionValues,
UintSize,
UintSize);
System.Buffer.BlockCopy(BitConverter.GetBytes(interval),
0,
inOptionValues,
UintSize * 2,
UintSize);
// call WSAIoctl via IOControl
s.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null);
}
}
}