Struct Service

Source
pub struct Service { /* private fields */ }
Available on crate feature sync only.
Expand description

High-level reactor-style SSDP service using mio.

Use a Service to discover network resources using SSDP, or to advertise network resources which your program provides. Or both.

The implementation integrates with the mio crate, which provides a “reactor-style” I/O API suited for running several I/O operations in a single thread. (SSDP, being relatively low-bandwidth and non-urgent, is unlikely to require any more high-performance I/O solution.) An alternative mechanism, crate::AsyncService, integrates directly with tokio instead of mio.

The implementation requires two UDP sockets: one bound to the well-known SSDP port number (1900) which subscribes to the multicast group, and a second bound to a random port for sending unicast searches and receiving unicast replies. (It would be possible to get by with a single socket if cotton-ssdp knew it was the only SSDP implementation running on that IP address – but if there might be other implementations running, it needs its own search socket in order not to steal other applications’ packets.)

For that reason, two MIO tokens are required; these should be passed to Service::new, which takes care of registering them with the MIO poller. Likewise, the main polling loop can indicate readiness on either token at any time, and the corresponding “*_ready” method on ServiceService::multicast_ready or Service::search_ready – should be called in response. All this can be seen in the ssdp-search-mio example, from which the example code below is adapted.

§Example subscriber

This code starts a search for all SSDP resources on the local network, from all network interfaces, and stores unique ones in a HashMap. The map will be populated as the MIO polling loop runs.

    let map = RefCell::new(HashMap::new());
    ssdp.subscribe(
        "ssdp:all",
        Box::new(move |r| {
            let mut m = map.borrow_mut();
            if let Notification::Alive {
                ref notification_type,
                ref unique_service_name,
                ref location,
            } = r {
                if !m.contains_key(unique_service_name) {
                    m.insert(unique_service_name.clone(), r.clone());
                }
            }
        }),
    );

§Example advertiser

This code sets up an advertisement for a (fictitious) resource, ostensibly available over HTTP on port 3333. The actual advertisements will be sent (and any incoming searches replied to) as the MIO polling loop runs.

(The UPnP Device Architecture specifies exactly what to advertise in the case of a UPnP implementation; this simpler example is not in itself compliant with that document.)

    let uuid = uuid::Uuid::new_v4();
    ssdp.advertise(
        uuid.to_string(),
        cotton_ssdp::Advertisement {
            notification_type: "test".to_string(),
            location: "http://127.0.0.1:3333/test".to_string(),
        },
    );

Notice that the URL in the location field uses the localhost IP address. The Service itself takes care of rewriting that, on a per-network-interface basis, to the IP address on which each SSDP peer will be able to reach the host where the Service is running. For instance, if your Ethernet IP address is 192.168.1.3, and your wifi IP address is 10.0.4.7, anyone listening to SSDP on Ethernet will see http://192.168.1.3:3333/test and anyone listening on wifi will see http://10.0.4.7:3333/test. (For how this is done, see the use of rewrite_host in Engine::on_data.)

§The polling loop

The actual MIO polling loop, mentioned above, should be written in the standard way common to all MIO applications. For instance, it might look like this:

    loop {
        poll.poll(&mut events, Some(ssdp.next_wakeup())).unwrap();

        if ssdp.next_wakeup() == std::time::Duration::ZERO {
            ssdp.wakeup();
        }

        for event in &events {
            match event.token() {
                SSDP_TOKEN1 => ssdp.multicast_ready(),
                SSDP_TOKEN2 => ssdp.search_ready(),
                // ... other tokens as required by the application ...
                _ => (),
            }
        }
    }

Implementations§

Source§

impl Service

Source

pub fn new(registry: &Registry, tokens: (Token, Token)) -> Result<Self, Error>

Create a new Service, including its two UDP sockets

And registers the sockets with the mio::Registry

§Errors

Can return a std::io::Error if any of the underlying socket calls fail.

Source

pub fn subscribe<A>( &mut self, notification_type: A, callback: Box<dyn Fn(&Notification)>, )
where A: Into<String>,

Subscribe to notifications about a particular service type

Or subscribe to “ssdp:all” for notifications about all service types.

This call also sends fresh search messages.

Source

pub fn advertise<USN>( &mut self, unique_service_name: USN, advertisement: Advertisement, )
where USN: Into<String>,

Advertise a local resource on the network

Source

pub fn deadvertise(&mut self, unique_service_name: &str)

Withdraw an advertisement for a local resource

For instance, it is “polite” to call this if shutting down cleanly.

Source

pub fn multicast_ready(&mut self)

Handler to be called when multicast socket is readable

Source

pub fn search_ready(&mut self)

Handler to be called when search socket is readable

Source

pub fn next_wakeup(&self) -> Duration

Time before next wakeup

Source

pub fn wakeup(&mut self)

Handler to be called when wakeup timer elapses

Auto Trait Implementations§

§

impl !Freeze for Service

§

impl !RefUnwindSafe for Service

§

impl !Send for Service

§

impl !Sync for Service

§

impl Unpin for Service

§

impl !UnwindSafe for Service

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V