Skip to content
File

Blob: archive/fft-benchmark/firmware/crates/esp32-radio/src/platform/http.rs

rust78 lines
1//! Blocking certificate-verified HTTPS, owned exclusively by signaling.
2use super::ffi;
3use crate::error::{Error, Result};
4use std::{
5 ffi::{CStr, c_void},
6 marker::PhantomData,
7 ptr::NonNull,
8 rc::Rc,
9 sync::atomic::{AtomicBool, Ordering},
10};
11 
12static HTTP_TAKEN: AtomicBool = AtomicBool::new(false);
13pub(crate) const RESPONSE_LIMIT: usize = 24_576;
14 
15#[derive(Debug)]
16pub(crate) struct Http {
17 handle: NonNull<c_void>,
18 _task: PhantomData<Rc<()>>,
19}
20 
21impl Http {
22 pub(crate) fn open() -> Result<Self> {
23 if HTTP_TAKEN.swap(true, Ordering::AcqRel) {
24 return Err(Error::new("HTTP task already initialized"));
25 }
26 loop {
27 // SAFETY: only the successful guard owner may initialize/synchronize
28 // SNTP. C owns all configuration; no Rust callback or borrowed memory.
29 match unsafe { ffi::radio_clock_sync() } {
30 1 => break,
31 -1 => return Err(Error::new("clock initialization failed")),
32 _ => super::log("Waiting for time synchronization before verified HTTPS"),
33 }
34 }
35 // SAFETY: C returns a fresh client owning all callback buffers. It uses
36 // compiled credentials internally; no secret enters Rust diagnostics.
37 let handle = NonNull::new(unsafe { ffi::radio_http_open() })
38 .ok_or(Error::new("HTTPS initialization failed"))?;
39 Ok(Self {
40 handle,
41 _task: PhantomData,
42 })
43 }
44 pub(crate) fn post(
45 &mut self,
46 path: &CStr,
47 body: &[u8],
48 out: &mut [u8],
49 ) -> Result<(i32, usize)> {
50 let mut used = 0;
51 // SAFETY: all pointers are live for this blocking call; output is uniquely
52 // borrowed and disjoint from body. C clears its borrowed POST field before
53 // return. Events use C-owned response storage, then copy within capacity.
54 let status = unsafe {
55 ffi::radio_http_post(
56 self.handle.as_ptr(),
57 path.as_ptr(),
58 body.as_ptr(),
59 body.len(),
60 out.as_mut_ptr(),
61 out.len(),
62 &mut used,
63 )
64 };
65 if used > out.len() {
66 return Err(Error::new("invalid HTTPS response length"));
67 }
68 Ok((status, used))
69 }
70}
71impl Drop for Http {
72 fn drop(&mut self) {
73 // SAFETY: all blocking calls/callbacks have returned; same task and sole
74 // owner. C cleans up the client before freeing its callback context.
75 unsafe { ffi::radio_http_free(self.handle.as_ptr()) };
76 }
77}