Covertness/coap-rs

Inject/queue a notification for the Server to dispatch

justinh-xacom opened this issue · 4 comments

I'd like to request a feature where once the coap-rs Server is running, the program that calls server.run() can inject/queue a notification packet for the Server to send. If the notification that was injected/queued is confirmable, then the confirmation response can be exposed via the same mechanism that other requests are exposed (e.g. via the server.run() closure).

This feature follows on from the disable_observe_handling() feature that I'm super grateful you implemented so quickly.

To summarise how and why I'm looking to use this new feature...

  • 'Program A' uses coap-rs to run a Server.
  • The Server receives a confirmable GET+OBS request for /some_path.
  • Because disable_observe_handling() is set, the request is forwarded to the server.run() closure.
  • When processing the GET+OBS request, the observer details (ip, port, token, and path) are stored externally (e.g. Redis).
  • At some stage in the future, 'Program B' (which monitors the observers stored within Redis), determines that a notification needs to be sent. When this occurs, it writes an instruction to a notify_queue (stored within Redis).
  • 'Program A' monitors the notify_queue and when a new entry is added, it is read from the queue, turned into a CoapRequest and passed to the coap-rs Server to internally queue and/or send to the observer.

Note: Initially, I had hoped that 'Program B' could send a notification packet to the observer itself, but I've found that this doesn't work, and I suspect it is because the Coap Client only accepts notifications from the Coap Server's IP:Port and not from a different IP:Port source.

Below is some prototype code that shows how I'm currently using coap-rs Server. I have some 'TO DO' comments where I could conceivably implement the new feature I'm requesting.

`fn run_server(server_settings: ServerSettings) {

let running = Arc::new(AtomicBool::new(true));
let running_setup = running.clone();
let running_monitor = running.clone();

// Set up the signal handler
ctrlc::set_handler(move || {
    running_setup.store(false, Ordering::SeqCst);
}).expect("Error setting Ctrl-C handler");

let rt = Runtime::new().unwrap();
rt.block_on(async move {
    let server_addr = server_settings.uri.clone();
    let mut server = Server::new_udp(server_addr).unwrap();
    server.disable_observe_handling(true).await;

    println!("Server up on {}", server_settings.uri.clone());

    // Spawn the CoAP server as a separate task
    let server_task = tokio::spawn(async move {
        server.run(move |request| {

            let running_copy = running.clone();
            let server_settings_copy = server_settings.clone();
            async move {
                let result = handle_request(request, running_copy, &server_settings_copy).await;
                if let Some(ref response) = result.response {
                    log_response(&response, &server_settings_copy);
                }
                // TO DO.. If the notify_waiting flag is set, then build the 
                // notification and pass it to server to internally queue and send when able
                return result;
            }
        }).await.unwrap();
    });

    // TO DO.. Spawn a task that monitors a Redis notify_queue and if an entry is found
    // toggle a notify_waiting flag within server_task. 

    // Detect and handle the program shutdown signal
    while running_monitor.load(Ordering::SeqCst) {

        tokio::time::sleep(Duration::from_secs(2)).await;
    }
    println!("Shutting down");
    server_task.abort();
});

}`

What do you think? Is my feature request doable/useful? Or is there a better way to do what I'm attempting to do?

Sorry, we may be able to disregard/close my feature request, as the CoAP client that I'm looking to interface with may be able to handle notifications that come from somewhere different to where the initial GET+OBS request was sent. e.g.

  • The CoAP client sends the GET+OBS request to the server IP targeting UDP port 5683.
  • The CoAP server (Program A) acknowledges the request.
  • The CoAP server stores the observer's IP, Port and Token within an observer list.
  • Then, a separate program (Program B, which may or may not run on a different server), decides that a notification needs to be sent to an observer.
  • Program B uses the observer IP, Port and Token from the observer list to send a notification packet that targets the observer's IP and Port.
  • However, the notification comes from a source IP:Port that is not the same as the Server IP and Port that the client's GET+OBS request initially targeted.
  • The CoAP client accepts the notification, and if the notification is confirmable, sends the acknowledgement to the notification sender (Program B) and not to the Server IP on UDP port 5683 (Program A).

Please give me a few days to confirm if I need the feature that my first post asked for. And if I no longer need this feature, and if nobody else adds a comment to say that they want this feature, I'll close it and apologise for wasting everybody's time.

I've confirmed that my distributed server approach does not work. i.e. A separate program that handles notifications separately to the main CoAP server is not feasible for the CoAP clients that my program needs to communicate with. The primary reason is that when we implement DTLS, I've been told that it will not be feasible to modify the CoAP client to accept notifications that come from a different IP:Port source.

So, to reword my feature request in simple terms...

Can a feature be added that allows the CoAP server, while running (i.e. while server.run() is listening for CoAP packets), to be told to send a notification packet to a specific CoAP observer?

I don't think it's appropriate to implement in a CoAP library. The library should only contain implementations of the protocol. You can implement it by your self.

Closed. Reopen it if you have any new problem about it.