/// <summary>
        /// Starts this SSDP listener. When this method was called, the listener will receive SSDP messages.
        /// </summary>
        public void Start()
        {
            lock (_cpData.SyncObj)
            {
                if (_isActive)
                {
                    throw new IllegalCallException("SSDPClientController is already active");
                }
                _isActive = true;
                IList <IPAddress> addresses = NetworkHelper.OrderAddressesByScope(NetworkHelper.GetUPnPEnabledIPAddresses(UPnPConfiguration.IP_ADDRESS_BINDINGS));

                // Add endpoints
                foreach (IPAddress address in addresses)
                {
                    AddressFamily family = address.AddressFamily;
                    if (family == AddressFamily.InterNetwork && !UPnPConfiguration.USE_IPV4)
                    {
                        continue;
                    }
                    if (family == AddressFamily.InterNetworkV6 && !UPnPConfiguration.USE_IPV6)
                    {
                        continue;
                    }
                    EndpointConfiguration config = new EndpointConfiguration
                    {
                        SSDPMulticastAddress = NetworkHelper.GetSSDPMulticastAddressForInterface(address),
                        EndPointIPAddress    = address
                    };

                    // Multicast receiver socket - used for receiving multicast messages
                    Socket socket = new Socket(family, SocketType.Dgram, ProtocolType.Udp);
                    config.SSDP_UDP_MulticastReceiveSocket = socket;
                    try
                    {
                        socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
                        NetworkHelper.BindAndConfigureSSDPMulticastSocket(socket, address);

                        StartMulticastReceive(new UDPAsyncReceiveState <EndpointConfiguration>(config, UPnPConsts.UDP_SSDP_RECEIVE_BUFFER_SIZE, socket));
                    }
                    catch (Exception) // SocketException, SecurityException
                    {
                        UPnPConfiguration.LOGGER.Info("SSDPClientController: Unable to bind to multicast address(es) for endpoint '{0}'",
                                                      NetworkHelper.IPAddrToString(config.EndPointIPAddress));
                    }

                    // Unicast sender and receiver socket - used for sending M-SEARCH queries and receiving its responses.
                    // We need a second socket here because the search responses which arrive at this port are structured
                    // in another way than the notifications which arrive at our multicast socket.
                    socket = new Socket(family, SocketType.Dgram, ProtocolType.Udp);
                    config.SSDP_UDP_UnicastSocket = socket;
                    try
                    {
                        socket.Bind(new IPEndPoint(config.EndPointIPAddress, 0));
                        _cpData.Endpoints.Add(config);
                        StartUnicastReceive(new UDPAsyncReceiveState <EndpointConfiguration>(config, UPnPConsts.UDP_SSDP_RECEIVE_BUFFER_SIZE, socket));
                    }
                    catch (Exception e) // SocketException, SecurityException
                    {
                        UPnPConfiguration.LOGGER.Info("SSDPClientController: Unable to bind to unicast address '{0}'", e,
                                                      NetworkHelper.IPAddrToString(config.EndPointIPAddress));
                    }
                }

                _expirationTimer = new Timer(OnExpirationTimerElapsed, null, EXPIRATION_TIMER_INTERVAL, EXPIRATION_TIMER_INTERVAL);
            }
        }
Example #2
0
        /// <summary>
        /// Configures the SSDP part of the given endpoint <paramref name="config"/>.
        /// Starts the SSDP UDP listener client for the given network endpoint.
        /// </summary>
        /// <param name="config">The endpoint configuration which should be started.</param>
        public void StartSSDPEndpoint(EndpointConfiguration config)
        {
            IPAddress     address = config.EndPointIPAddress;
            AddressFamily family  = address.AddressFamily;

            config.SSDPMulticastAddress = NetworkHelper.GetSSDPMulticastAddressForInterface(address);
            config.SSDPSearchPort       = UPnPConsts.DEFAULT_SSDP_SEARCH_PORT;

            // Multicast socket - used for sending and receiving multicast messages
            Socket socket = new Socket(family, SocketType.Dgram, ProtocolType.Udp);

            config.SSDP_UDP_MulticastReceiveSocket = socket;
            try
            {
                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
                NetworkHelper.BindAndConfigureSSDPMulticastSocket(socket, address);
                StartReceive(new UDPAsyncReceiveState <EndpointConfiguration>(config, UPnPConsts.UDP_SSDP_RECEIVE_BUFFER_SIZE, socket));
            }
            catch (Exception e) // SocketException, SecurityException
            {
                UPnPConfiguration.LOGGER.Warn("SSDPServerController: Unable to bind to multicast address(es) for endpoint '{0}'", e,
                                              NetworkHelper.IPAddrToString(address));
            }

            // Unicast sender and receiver socket - used for receiving unicast M-SEARCH queries and sending M-SEARCH responses
            socket = new Socket(family, SocketType.Dgram, ProtocolType.Udp);
            config.SSDP_UDP_UnicastSocket = socket;
            try
            {
                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
                try
                {
                    // Try to bind our unicast receiver socket to the default SSDP port
                    socket.Bind(new IPEndPoint(address, config.SSDPSearchPort));
                }
                catch (SocketException e)
                {
                    if (e.SocketErrorCode != SocketError.AddressAlreadyInUse)
                    {
                        throw;
                    }
                    // If binding to the default SSDP port doesn't work, try a random port...
                    socket.Bind(new IPEndPoint(address, 0));
                    // ... which will be stored in the SSDPSearchPort variable which will be used for the SEARCHPORT.UPNP.ORG SSDP header.
                    config.SSDPSearchPort = ((IPEndPoint)socket.LocalEndPoint).Port;
                }
                UPnPConfiguration.LOGGER.Info("UPnPServerController: SSDP enabled for IP endpoint '{0}', search port is {1}",
                                              NetworkHelper.IPAddrToString(address), config.SSDPSearchPort);
                // The following is necessary to retrieve the remote IP address when we receive SSDP packets
                if (family == AddressFamily.InterNetwork)
                {
                    try
                    {
                        // Receiving options
                        socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true);
                        // Sending options
                        socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive,
                                               UPnPConfiguration.SSDP_UDP_TTL_V4);
                    }
                    catch (SocketException e)
                    {
                        UPnPConfiguration.LOGGER.Warn("GENAServerController: Could not set IPv4 options", e);
                    }
                }
                else
                {
                    try
                    {
                        // Receiving options
                        socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.PacketInformation, true);
                        // Sending options
                        socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.HopLimit,
                                               UPnPConfiguration.SSDP_UDP_HOP_LIMIT_V6);
                    }
                    catch (SocketException e)
                    {
                        UPnPConfiguration.LOGGER.Warn("GENAServerController: Could not set IPv6 options", e);
                    }
                }
                StartReceive(new UDPAsyncReceiveState <EndpointConfiguration>(config, UPnPConsts.UDP_SSDP_RECEIVE_BUFFER_SIZE, socket));
            }
            catch (Exception e) // SocketException, SecurityException
            {
                UPnPConfiguration.LOGGER.Warn("SSDPServerController: Unable to bind to unicast address '{0}'", e,
                                              NetworkHelper.IPAddrToString(address));
            }
        }