-
Notifications
You must be signed in to change notification settings - Fork 183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: captive portal dns (+lwip apis) #20
Conversation
@@ -0,0 +1,305 @@ | |||
use core::mem; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I must say, I LOVE the idea of having a Captive Portal!
What I don't love that much:
- Overall, the code feels very low level (as if we are coding in C, via Rust) - I'll comment more below
- It is part of
esp-idf-svc
but I'm not sure what it is doing here? This is a generic DNS server, which can - just as well - be coded against Rust's STD APIs (correct me if I'm wrong!) - or better yet - against the embedded-nal so that it does have ano_std
story as well. (embedded-nal
traits do have STD implementations too, and if these are lacking, we can implement / patch / upstream our own changes.). So I'm very much in favor of moving this intoembedded-svc
(which depends onno-std-net
already anyway) - possibly behind a feature toggle. - As for what would be the use-case of that? Well, I might want to use a captive dns portal on the Raspberry Pi too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code is indeed C converted to Rust, but not quite at the point where I'm super happy with the "Rustyness" of it yet
Sure, it would be nice to have it generic.
But my use case wasn't quite as generic, so I implemented it specifically for the esp right now.
embedded-nal
seems nice, hadn't heard of it before.
I feel like someone else must have already implemented a captive portal dns in rust that's more generic, though. (not that I checked and not that I'm opposed to make this more generic)
This PR also doesn't have to be merged, it was more of an "are you interested in having this here", because I had already built it
|
||
impl CaptivePortalDns { | ||
pub fn new() -> Self { | ||
CaptivePortalDns { task_handle: None } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the desire to stay no_std
compatible is what brought you into exposing bits and pieces for FreeRTOS? How about we take a simple trait instead, that would allow us to spawn a thread? We can even provide an implementation of the trait when Rust STD is enabled, and provide additional constructor which does not take the trait, for STD mode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the desire to stay
no_std
compatible is what brought you into exposing bits and pieces for FreeRTOS?
Yes
How about we take a simple trait instead, that would allow us to spawn a thread? We can even provide an implementation of the trait when Rust STD is enabled, and provide additional constructor which does not take the trait, for STD mode.
As in, implement it with std::thread
when we're using std
and otherwise add an impl with FreeRTOS?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As in implement it with std::thread
when we are using std
and don't provide an implementation at all for no_std
. With no_std
, user would be on their own to provide an implementation in whatever way they feel like.
It boils down to the following: we have to keep the esp-idf-svc
surface small, clean and easy to explain by exposing Rust-safe, self-contained pieces of functionality, - ideally - behind generic traits. The emphasis being on safe and self-contained. We cannot just go there and expose random bits and pieces of all the raw level unsafe APIs that are out there in the ESP-IDF. For example, in your "basic freertos task api" what you have exposed from FreeRTOS is just a way to start a task (and that is always pinned to a core, if I'm not mistaken). Is that API generic enough so that folks can use it without calling other, unsafe Freertos APIs? Well, no. For one, the queueing and synchronization primitives of freertos are not exposed as safe APIs, because you did not need them for your particular case. But very likely people will need these to do something meaningful with freertos. So, how are we evolving your Freertos code? Is it going to - at some point in time - reach a feature parity with the unsafe freertos APIs?
- If yes, then we are basically creating a whole Freertos wrapper, and shouldn't we then instead work towards making some of the Freertos Rust wrappers interop-ing with
esp-idf-svc
interop-ing withesp-idf-sys
? - If no, aren't we in a better position by saying to folks that there are NO freertos safe APIs, and they should just use the unsafe bindings which are out there in
esp-idf-sys
?
ip_addr: u32, | ||
} | ||
|
||
fn parse_dns_name(raw_name: *mut u8, parsed_name: &mut [u8]) -> *mut u8 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This and the next function are littered with unsafe
statements. Would it be possible to stay in Rust safe-land for parsing this stuff? Only if possible?
answer.class = htons(qd_class); | ||
answer.ttl = htonl(ANS_TTL_SEC); | ||
|
||
let mut ip_info = esp_netif_ip_info_t::default(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In an implementation which is independent of ESP-IDF, we would want the IP address to be abstracted away, via a trait, or passed at construction/start time.
OK so the real trickiness of all this code is in Now, the nice thing is - everything in I still don't like it that there are so many unsafe statements in the above function, but my little mind cannot figure out for now how to go from byte buffers to Rust structures and back with less unsafe, so the unsafes will stay intact (for now). My plan is the following:
Any glaring holes in this plan that you might spot? |
Should be possible to use an iterator I think, there were more pointers in there I converted Just for reference, this is the example I converted https://github.com/espressif/esp-idf/blob/4a011f318377ab717b9dc459019c1055602c93ff/examples/protocols/http_server/captive_portal/main/dns_server.c
Could also pass in an IP when you start the dns server, it's probably unlikely to change
Would be great to have an impl with |
I was halfway there in removing the unsafes over the weekend when I found this. To be expected of course that such a thing exists in the first place. I'm switching to it instead. |
Closing in favor of esp-rs/embedded-svc@759b996 WIP and not tested yet, but I hope to get it working over the weekend. |
Implemented the captive portal dns from the esp idf example
To use it:
/
(important!)The captive portal should show up when you log into wifi
Example gist with working code
Depends on #15 (and in turn #13)