开发者

How to use MLDv2 in C# (IPv6 Multicast)

In IPv4, [Version 3 of IGMP adds support for "source filtering", that is, the ability for a system to report interest in receiving packets *only* from specific source addresses.][1]

I am using IGMPv3 in a C# application to support this behaviour. Here is how I do it.

I am now in the process to add support to IPv开发者_Python百科6 in my application and I need to get the same behaviour as in IPv4. From what I've read, the equivalent protocol to IGMPv3 in IPv6 is MLDv2. Has someone any idea on how to implement this in C# with Socket?

Thanks!


The RFC3678 protocol independent API is only available in Vista+ which might explain the problem.

If C# runtime does fully support IPv6 you will have to try to match the GROUP_REQ or GROUP_SOURCE_REQ structures. There is no IPv6 specific API for SSM matching the IPv4 API because developers finally abandoned the inane duplication of APIs and finally settled on the one super set.

It is unfortunately likely that C# implements ipv6_mreq for AddMembership and AddSourceMembership fails. The documentation is completely absent on detail.

All the SocketOptionName values required are not defined in C#:

/* RFC 3678 */
#define MCAST_JOIN_GROUP       41
#define MCAST_LEAVE_GROUP      42
#define MCAST_BLOCK_SOURCE     43
#define MCAST_UNBLOCK_SOURCE   44
#define MCAST_JOIN_SOURCE_GROUP        45
#define MCAST_LEAVE_SOURCE_GROUP       46
#define MCAST_MSFILTER         47


To follow up on the answer of Steve-o, it is still possible to do source filtering in IPv6 in C# even if the System.Net.Sockets.SocketOptionName enumeration doesn't define the required options by casting the number directly.

(SocketOptionName) 45; //MCAST_JOIN_SOURCE_GROUP

The function SetSocketOption of the socket will let the call go to the "windows socket" even if the option is not recognized. The real struggle becomes the data structure itself that needs to be sent along side the option. To set source filtering the data structure must be like this one: group_source_req. The previous struct is using a sockaddr_storage that is usually inside a union with sockaddr_in and sockaddr_in6. To replicate this behavior we can define the same structs like this:

private unsafe struct sockaddr_storage
{
    public short ss_family;             //2
    private fixed byte __ss_pad1[6];    //6
    private Int64 __ss_align;           //8
    private fixed byte __ss_pad2[112];  //112
}
private unsafe struct sockaddr_in
{
    public ushort sin_family;       //2
    public ushort sin_port;         //2
    public fixed byte sin_addr[4];  //4
    private fixed byte sub_zero[8]; //8
 }
private unsafe struct sockaddr_in6
{
    public ushort sin6_family;       //2
    public ushort sin6_port;         //2
    public int sin6_flowinfo;        //4
    public fixed byte sin6_addr[16]; //16
    public uint sin6_scope_id;       //4
}
private struct group_source_req
{
    public uint gr_interface;           //4
    //Compiler add a padding here:      //4
    public sockaddr_storage gr_group;   //128
    public sockaddr_storage gr_source;  //128
}

You can now create a sockaddr_in6 by doing this:

sockaddr_in6 sockIn = new sockaddr_in6
{
    sin6_family = (ushort) endPoint.AddressFamily,
    sin6_port = (ushort)endPoint.Port,
    sin6_scope_id = 0
};
for (int i = 0; i < endPoint.Address.GetAddressBytes().Length; i++)
{
    sockIn.sin6_addr[i] = endPoint.Address.GetAddressBytes()[i];
}

The bytes of the sockaddr_in6 can now be extracted by using the solution provided here and copied directly into a previously created sockaddr_storage:

sockaddr_storage sock = new sockaddr_storage
{
    ss_family = (short)endPoint.AddressFamily
};
//[...]
byte[] sockInData = getBytes(sockIn);
byte* sockData = (byte*) &sock;
for (int i = 0; i < sockInData.Length; i++)
{
    sockData [i] = sockInData[i];
}

Now that you have a sockaddr_storage you can assign it to group_source_req and extract the data of the group_source_req like we did earlier and use this as the value when you set the option.

socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName) 45, /*data extracted from group_source_req*/);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜