public async Task <TransmissionResult> SendAsync(Transmission msg, IPAddress groupIp, int port,
                                                         EMulticastInterface iface, IPAddress specificIface = null, int ttl = 1)
        {
            Validate(groupIp, port);

            if (_sendUdpClient == null || _sendUdpClient.Client.AddressFamily != groupIp.AddressFamily)
            {
                if (_sendUdpClient != null)
                {
                    _sendUdpClient.Close();
                }

                _sendUdpClient = new UdpClient(groupIp.AddressFamily);
                _sendUdpClient.Client.Bind(new IPEndPoint(
                                               _sendUdpClient.Client.AddressFamily == AddressFamily.InterNetworkV6 ?
                                               IPAddress.IPv6Any : IPAddress.Any, 0));
            }

            SetSendTTL(_sendUdpClient, ttl);

            IPEndPoint from           = _sendUdpClient.Client.LocalEndPoint as IPEndPoint;
            IPEndPoint to             = new IPEndPoint(groupIp, port);
            var        sendInterfaces = new List <int>();

            if (iface == EMulticastInterface.All)
            {
                foreach (var ni in NetworkUtils.GetActiveInterfaces())
                {
                    sendInterfaces.Add(_sendUdpClient.Client.AddressFamily == AddressFamily.InterNetworkV6
                        ? ni.IPv6.Index : ni.IPv4.Index);
                }
            }
            else if (iface == EMulticastInterface.Specific)
            {
                int idx = NetworkUtils.GetBestMulticastInterfaceIndex(specificIface);
                if (idx == -1)
                {
                    idx = 0; // fall back default to default if not found.
                }

                sendInterfaces.Add(idx);
            }
            else
            {
                sendInterfaces.Add(0); // use default interface.
            }


            foreach (var ifaceIndex in sendInterfaces)
            {
                SetSendInterface(_sendUdpClient, ifaceIndex);
                await _sendUdpClient.SendAsync(msg.Data, msg.Data.Length, to);
            }

            return(new TransmissionResult {
                From = from, To = to
            });
        }
        public void JoinASM(IPAddress groupIp, int port,
                            EMulticastInterface iface, IPAddress specificIface = null)
        {
            Validate(groupIp, port);

            if (_udpClient != null)
            {
                return; // already started.
            }
            _udpClient = new UdpClient(groupIp.AddressFamily);
            Socket socket = _udpClient.Client;

            socket.SetSocketOption(
                SocketOptionLevel.Socket,
                SocketOptionName.ReuseAddress,
                true
                );

            var bindInterface = specificIface;

            if (iface != EMulticastInterface.Specific)
            {
                bindInterface = (socket.AddressFamily == AddressFamily.InterNetworkV6 ?
                                 IPAddress.IPv6Any : IPAddress.Any);
            }
            socket.Bind(new IPEndPoint(bindInterface, port));

            var joinInterfaces = new List <int>();

            if (iface == EMulticastInterface.All)
            {
                foreach (var ni in NetworkUtils.GetActiveInterfaces())
                {
                    joinInterfaces.Add(socket.AddressFamily == AddressFamily.InterNetworkV6
                        ? ni.IPv6.Index : ni.IPv4.Index);
                }
            }
            else if (iface == EMulticastInterface.Specific)
            {
                int best = NetworkUtils.GetBestMulticastInterfaceIndex(specificIface);
                if (best == -1)
                {
                    best = 0;
                }
                joinInterfaces.Add(best);
            }
            else if (iface == EMulticastInterface.Default)
            {
                joinInterfaces.Add(0); // 0 = default.
            }

            foreach (int ifaceIndex in joinInterfaces)
            {
                if (socket.AddressFamily == AddressFamily.InterNetwork)
                {
                    MulticastOption opt = new MulticastOption(
                        groupIp, ifaceIndex);

                    socket.SetSocketOption(SocketOptionLevel.IP,
                                           SocketOptionName.AddMembership, opt);
                }
                else if (socket.AddressFamily == AddressFamily.InterNetworkV6)
                {
                    IPv6MulticastOption optv6 = new IPv6MulticastOption(
                        groupIp, ifaceIndex);

                    socket.SetSocketOption(SocketOptionLevel.IPv6,
                                           SocketOptionName.AddMembership, optv6);
                }
            }

            StatusChanged?.Invoke(this,
                                  new UdpMulticastClientStatusEventArgs(true)
            {
                MulticastGroup     = new IPEndPoint(groupIp, port),
                MulticastInterface = iface,
                SpecificInterface  = specificIface
            }
                                  );

            StartReceive();
        }
        public void JoinSSM(IPAddress groupIp, IPAddress sourceIp, int port,
                            EMulticastInterface iface, IPAddress specificIface = null)
        {
            Validate(groupIp, port);

            if (_udpClient != null)
            {
                return; // already started.
            }
            _udpClient = new UdpClient(groupIp.AddressFamily);
            Socket socket = _udpClient.Client;

            socket.SetSocketOption(
                SocketOptionLevel.Socket,
                SocketOptionName.ReuseAddress,
                true
                );

            var bindInterface = specificIface;

            if (iface != EMulticastInterface.Specific)
            {
                bindInterface = (socket.AddressFamily == AddressFamily.InterNetworkV6 ?
                                 IPAddress.IPv6Any : IPAddress.Any);
            }
            socket.Bind(new IPEndPoint(bindInterface, port));

            var joinInterfaces = new List <int>();

            if (iface == EMulticastInterface.All)
            {
                foreach (var ni in NetworkUtils.GetActiveInterfaces())
                {
                    joinInterfaces.Add(socket.AddressFamily == AddressFamily.InterNetworkV6
                        ? ni.IPv6.Index : ni.IPv4.Index);
                }
            }
            else if (iface == EMulticastInterface.Specific)
            {
                int best = NetworkUtils.GetBestMulticastInterfaceIndex(specificIface);
                if (best == -1)
                {
                    best = 0;
                }
                joinInterfaces.Add(best);
            }
            else if (iface == EMulticastInterface.Default)
            {
                joinInterfaces.Add(0); // 0 = default.
            }

            foreach (int ifaceIndex in joinInterfaces)
            {
                if (socket.AddressFamily == AddressFamily.InterNetwork)
                {
                    var bin = new byte[12];
                    Buffer.BlockCopy(groupIp.GetAddressBytes(), 0, bin, 0, 4);
                    Buffer.BlockCopy(sourceIp.GetAddressBytes(), 0, bin, 4, 4);
                    Buffer.BlockCopy(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(ifaceIndex)), 0, bin, 8, 4);

                    socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddSourceMembership, bin);
                }
                else if (socket.AddressFamily == AddressFamily.InterNetworkV6)
                {
                    // fill data as in GROUP_SOURCE_REQ struct
                    var bin = CreateGroupSourceReg(sourceIp, groupIp, ifaceIndex);

                    socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)45, bin);
                }
            }

            StatusChanged?.Invoke(this,
                                  new UdpMulticastClientStatusEventArgs(true)
            {
                MulticastGroup     = new IPEndPoint(groupIp, port),
                MulticastInterface = iface,
                SpecificInterface  = specificIface
            }
                                  );

            StartReceive();
        }