Come utilizzare MLDV2 in C# (multicast IPv6)
Domanda
Sto usando IGMPV3 in un'applicazione C# per supportare questo comportamento. Ecco come lo faccio.
Ora sono in corso per aggiungere supporto a IPv6 nella mia applicazione e devo ottenere lo stesso comportamento di IPv4. Da quello che ho letto, il protocollo equivalente a IGMPV3 in IPv6 è Mldv2. Qualcuno ha qualche idea su come implementarlo in C# con socket?
Grazie!
Soluzione
Il RFC3678 L'API indipendente del protocollo è disponibile solo in Vista+, il che potrebbe spiegare il problema.
Se il runtime c# supporta completamente IPv6 dovrai provare ad abbinare il Group_req o Group_source_req strutture. Non esiste un'API specifica IPv6 per SSM corrispondente all'API IPv4 perché gli sviluppatori hanno finalmente abbandonato l'inano duplicazione delle API e infine si sono stabiliti su un unico super set.
Purtroppo è probabile che c# implementa ipv6_mreq per AddMembership
e AddSourceMembership
non riesce. La documentazione è completamente assente nei dettagli.
Tutti i SocketOptionName
I valori richiesti non sono definiti 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
Altri suggerimenti
Per seguire la risposta di Steve-O, è ancora possibile eseguire il filtraggio di origine in IPv6 in C# anche se System.Net.sockets.SocketOptionName Enumeration non definisce le opzioni richieste lanciando direttamente il numero.
(SocketOptionName) 45; //MCAST_JOIN_SOURCE_GROUP
Il setSocketOption della funzione del socket consentirà alla chiamata di andare al "socket windows" anche se l'opzione non è riconosciuta. La vera lotta diventa la struttura dei dati stessa che deve essere inviata accanto all'opzione. Per impostare il filtro della sorgente, la struttura dei dati deve essere come questa: group_source_req. La struttura precedente sta usando un file Sockaddr_Storage che di solito è all'interno di un'unione con Sockaddr_in e Sockaddr_in6. Per replicare questo comportamento possiamo definire le stesse strutture come questa:
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
}
Ora puoi creare un Sockaddr_in6 facendo questo:
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];
}
I byte del Sockaddr_in6 possono ora essere estratti utilizzando la soluzione fornita qui e copiato direttamente in un Sockaddr_Storage precedentemente creato:
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];
}
Ora che hai un Sockaddr_Storage, puoi assegnarlo a Group_Source_req ed estrarre i dati del gruppo_source_req come abbiamo fatto prima e usarlo come valore quando si imposta l'opzione.
socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName) 45, /*data extracted from group_source_req*/);