nginx_sys/
lib.rs

1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3#![no_std]
4
5pub mod detail;
6mod event;
7#[cfg(ngx_feature = "http")]
8mod http;
9mod queue;
10mod rbtree;
11#[cfg(ngx_feature = "stream")]
12mod stream;
13mod string;
14
15use core::ptr;
16
17#[doc(hidden)]
18mod bindings {
19    #![allow(unknown_lints)] // unnecessary_transmutes
20    #![allow(missing_docs)]
21    #![allow(non_upper_case_globals)]
22    #![allow(non_camel_case_types)]
23    #![allow(non_snake_case)]
24    #![allow(dead_code)]
25    #![allow(clippy::all)]
26    #![allow(improper_ctypes)]
27    #![allow(rustdoc::broken_intra_doc_links)]
28    #![allow(unnecessary_transmutes)]
29    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
30}
31#[doc(no_inline)]
32pub use bindings::*;
33pub use event::*;
34#[cfg(ngx_feature = "http")]
35pub use http::*;
36pub use queue::*;
37pub use rbtree::*;
38#[cfg(ngx_feature = "stream")]
39pub use stream::*;
40
41/// Default alignment for pool allocations.
42pub const NGX_ALIGNMENT: usize = NGX_RS_ALIGNMENT;
43
44// Check if the allocations made with ngx_palloc are properly aligned.
45// If the check fails, objects allocated from `ngx_pool` can violate Rust pointer alignment
46// requirements.
47const _: () = assert!(core::mem::align_of::<ngx_str_t>() <= NGX_ALIGNMENT);
48
49impl ngx_command_t {
50    /// Creates a new empty [`ngx_command_t`] instance.
51    ///
52    /// This method replaces the `ngx_null_command` C macro. This is typically used to terminate an
53    /// array of configuration directives.
54    ///
55    /// [`ngx_command_t`]: https://nginx.org/en/docs/dev/development_guide.html#config_directives
56    pub const fn empty() -> Self {
57        Self {
58            name: ngx_str_t::empty(),
59            type_: 0,
60            set: None,
61            conf: 0,
62            offset: 0,
63            post: ptr::null_mut(),
64        }
65    }
66}
67
68impl ngx_module_t {
69    /// Create a new `ngx_module_t` instance with default values.
70    pub const fn default() -> Self {
71        Self {
72            ctx_index: ngx_uint_t::MAX,
73            index: ngx_uint_t::MAX,
74            name: ptr::null_mut(),
75            spare0: 0,
76            spare1: 0,
77            version: nginx_version as ngx_uint_t,
78            signature: NGX_RS_MODULE_SIGNATURE.as_ptr(),
79            ctx: ptr::null_mut(),
80            commands: ptr::null_mut(),
81            type_: 0,
82            init_master: None,
83            init_module: None,
84            init_process: None,
85            init_thread: None,
86            exit_thread: None,
87            exit_process: None,
88            exit_master: None,
89            spare_hook0: 0,
90            spare_hook1: 0,
91            spare_hook2: 0,
92            spare_hook3: 0,
93            spare_hook4: 0,
94            spare_hook5: 0,
95            spare_hook6: 0,
96            spare_hook7: 0,
97        }
98    }
99}
100
101impl ngx_variable_value_t {
102    /// Returns the contents of this variable value as a byte slice.
103    pub fn as_bytes(&self) -> &[u8] {
104        match self.len() {
105            0 => &[],
106            // SAFETY: data for non-empty value must be a valid well-aligned pointer.
107            len => unsafe { core::slice::from_raw_parts(self.data, len as usize) },
108        }
109    }
110}
111
112impl AsRef<[u8]> for ngx_variable_value_t {
113    fn as_ref(&self) -> &[u8] {
114        self.as_bytes()
115    }
116}
117
118/// Returns the error code of the last failed operation (`errno`).
119#[inline]
120pub fn ngx_errno() -> ngx_err_t {
121    // SAFETY: GetLastError takes no arguments and reads a thread-local variable
122    #[cfg(windows)]
123    let err = unsafe { GetLastError() };
124
125    #[cfg(not(windows))]
126    let err = errno::errno().0;
127
128    err as ngx_err_t
129}
130
131/// Sets the error code (`errno`).
132#[inline]
133pub fn ngx_set_errno(err: ngx_err_t) {
134    #[cfg(windows)]
135    // SAFETY: SetLastError takes one argument by value and updates a thread-local variable
136    unsafe {
137        SetLastError(err as _)
138    }
139    #[cfg(not(windows))]
140    errno::set_errno(errno::Errno(err as _))
141}
142
143/// Returns the error code of the last failed sockets operation.
144#[inline]
145pub fn ngx_socket_errno() -> ngx_err_t {
146    // SAFETY: WSAGetLastError takes no arguments and reads a thread-local variable
147    #[cfg(windows)]
148    let err = unsafe { WSAGetLastError() };
149
150    #[cfg(not(windows))]
151    let err = errno::errno().0;
152
153    err as ngx_err_t
154}
155
156/// Sets the error code of the sockets operation.
157#[inline]
158pub fn ngx_set_socket_errno(err: ngx_err_t) {
159    #[cfg(windows)]
160    // SAFETY: WSaSetLastError takes one argument by value and updates a thread-local variable
161    unsafe {
162        WSASetLastError(err as _)
163    }
164    #[cfg(not(windows))]
165    errno::set_errno(errno::Errno(err as _))
166}
167
168/// Returns a non cryptograhpically-secure pseudo-random integer.
169#[inline]
170pub fn ngx_random() -> core::ffi::c_long {
171    #[cfg(windows)]
172    unsafe {
173        // Emulate random() as Microsoft CRT does not provide it.
174        // rand() should be thread-safe in the multi-threaded CRT we link to, but will not be seeded
175        // outside of the main thread.
176        let x: u32 = ((rand() as u32) << 16) ^ ((rand() as u32) << 8) ^ (rand() as u32);
177        (0x7fffffff & x) as _
178    }
179    #[cfg(not(windows))]
180    unsafe {
181        random()
182    }
183}
184
185/// Causes the calling thread to relinquish the CPU.
186#[inline]
187pub fn ngx_sched_yield() {
188    #[cfg(windows)]
189    unsafe {
190        SwitchToThread()
191    };
192    #[cfg(all(not(windows), ngx_feature = "have_sched_yield"))]
193    unsafe {
194        sched_yield()
195    };
196    #[cfg(not(any(windows, ngx_feature = "have_sched_yield")))]
197    unsafe {
198        usleep(1)
199    }
200}
201
202/// Returns cached timestamp in seconds, updated at the start of the event loop iteration.
203///
204/// Can be stale when accessing from threads, see [ngx_time_update].
205#[inline]
206pub fn ngx_time() -> time_t {
207    // SAFETY: ngx_cached_time is initialized before any module code can run
208    unsafe { (*ngx_cached_time).sec }
209}
210
211/// Returns cached time, updated at the start of the event loop iteration.
212///
213/// Can be stale when accessing from threads, see [ngx_time_update].
214/// A cached reference to the ngx_timeofday() result is guaranteed to remain unmodified for the next
215/// NGX_TIME_SLOTS seconds.
216#[inline]
217pub fn ngx_timeofday() -> &'static ngx_time_t {
218    // SAFETY: ngx_cached_time is initialized before any module code can run
219    unsafe { &*ngx_cached_time }
220}
221
222/// Initialize a list, using a pool for the backing memory, with capacity to store the given number
223/// of elements and element size.
224///
225/// # Safety
226/// * `list` must be non-null
227/// * `pool` must be a valid pool
228#[inline]
229pub unsafe fn ngx_list_init(
230    list: *mut ngx_list_t,
231    pool: *mut ngx_pool_t,
232    n: ngx_uint_t,
233    size: usize,
234) -> ngx_int_t {
235    unsafe {
236        (*list).part.elts = ngx_palloc(pool, n * size);
237        if (*list).part.elts.is_null() {
238            return NGX_ERROR as ngx_int_t;
239        }
240        (*list).part.nelts = 0;
241        (*list).part.next = ptr::null_mut();
242        (*list).last = ptr::addr_of_mut!((*list).part);
243        (*list).size = size;
244        (*list).nalloc = n;
245        (*list).pool = pool;
246        NGX_OK as ngx_int_t
247    }
248}
249
250/// Add a key-value pair to an nginx table entry (`ngx_table_elt_t`) in the given nginx memory pool.
251///
252/// # Arguments
253///
254/// * `table` - A pointer to the nginx table entry (`ngx_table_elt_t`) to modify.
255/// * `pool` - A pointer to the nginx memory pool (`ngx_pool_t`) for memory allocation.
256/// * `key` - The key string to add to the table entry.
257/// * `value` - The value string to add to the table entry.
258///
259/// # Safety
260/// This function is marked as unsafe because it involves raw pointer manipulation and direct memory
261/// allocation using `str_to_uchar`.
262///
263/// # Returns
264/// An `Option<()>` representing the result of the operation. `Some(())` indicates success, while
265/// `None` indicates a null table pointer.
266///
267/// # Example
268/// ```rust
269/// # use nginx_sys::*;
270/// # unsafe fn example(pool: *mut ngx_pool_t, headers: *mut ngx_list_t) {
271/// // Obtain a pointer to the nginx table entry
272/// let table: *mut ngx_table_elt_t = ngx_list_push(headers).cast();
273/// assert!(!table.is_null());
274/// let key: &str = "key"; // The key to add
275/// let value: &str = "value"; // The value to add
276/// let result = add_to_ngx_table(table, pool, key, value);
277/// # }
278/// ```
279pub unsafe fn add_to_ngx_table(
280    table: *mut ngx_table_elt_t,
281    pool: *mut ngx_pool_t,
282    key: impl AsRef<[u8]>,
283    value: impl AsRef<[u8]>,
284) -> Option<()> {
285    if let Some(table) = table.as_mut() {
286        let key = key.as_ref();
287        table.key = ngx_str_t::from_bytes(pool, key)?;
288        table.value = ngx_str_t::from_bytes(pool, value.as_ref())?;
289        table.lowcase_key = ngx_pnalloc(pool, table.key.len).cast();
290        if table.lowcase_key.is_null() {
291            return None;
292        }
293        table.hash = ngx_hash_strlow(table.lowcase_key, table.key.data, table.key.len);
294        return Some(());
295    }
296    None
297}