Как использовать MLDv2 в C # (IPv6 Multicast) - PullRequest
0 голосов
/ 08 сентября 2011


В IPv4 версии 3 IGMP добавлена ​​поддержка «фильтрации источников», то есть способность системы сообщать о заинтересованности в получении пакетов только с определенных адресов источника.

Я использую IGMPv3 в приложении C # для поддержки этого поведения. Вот как я это делаю.

Сейчас я нахожусь в процессе добавления поддержки IPv6 в моем приложении, и мне нужно получить то же поведение, что и в IPv4. Из того, что я прочитал, эквивалентный протокол для IGMPv3 в IPv6 - MLDv2 . Кто-нибудь есть идеи о том, как реализовать это в C # с Socket?

Спасибо!

Ответы [ 2 ]

1 голос
/ 09 сентября 2011

API-интерфейс, независимый от протокола RFC3678 , доступен только в Vista +, что может объяснить проблему.

Если среда выполнения C # полностью поддерживает IPv6, вам придется попытаться соответствовать структурам GROUP_REQ или GROUP_SOURCE_REQ . Не существует специального API IPv6 для SSM, соответствующего API IPv4, потому что разработчики, наконец, отказались от бессмысленного дублирования API и в итоге остановились на одном суперсете.

К сожалению, вероятно, что C # реализует ipv6_mreq для AddMembership и AddSourceMembership не удается. Документация полностью отсутствует на деталях.

Все необходимые значения SocketOptionName не определены в 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
0 голосов
/ 22 ноября 2017

Чтобы проконтролировать ответ Steve-o, все еще возможно выполнить фильтрацию исходного кода в IPv6 в C #, даже если перечисление System.Net.Sockets.SocketOptionName не определяет требуемые параметры путем непосредственного приведения числа.

(SocketOptionName) 45; //MCAST_JOIN_SOURCE_GROUP

Функция SetSocketOption сокета разрешит вызову перейти к «сокету Windows», даже если опция не распознана.Настоящей борьбой становится сама структура данных, которую необходимо отправить вместе с опцией.Чтобы установить фильтрацию источника, структура данных должна быть такой: group_source_req .Предыдущая структура использует sockaddr_storage , который обычно находится внутри объединения с sockaddr_in и sockaddr_in6 .Чтобы воспроизвести это поведение, мы можем определить такие же структуры, как это:

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
}

Теперь вы можете создать sockaddr_in6, выполнив следующее:

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];
}

Теперь можно извлечь байты sockaddr_in6.используя предоставленное решение здесь и скопировав его непосредственно в ранее созданное 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];
}

Теперь, когда у вас есть sockaddr_storage, вы можете назначить его для group_source_req и извлечь данные из group_source_req какмы делали это раньше и использовали это значение в качестве значения при установке опции.

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