Skip to content

Commit

Permalink
feat!: foreign type wrappers for ngx_connection_t
Browse files Browse the repository at this point in the history
  • Loading branch information
bavshin-f5 committed Feb 13, 2025
1 parent 092f534 commit 24b41b1
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ repository.workspace = true
rust-version.workspace = true

[dependencies]
errno = "0.3.9"
foreign-types = "0.5.0"
libc = "0.2.169"
nginx-sys = { path = "nginx-sys", default-features=false, version = "0.5.0"}

[features]
Expand Down
137 changes: 137 additions & 0 deletions src/core/connection.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
use std::mem::MaybeUninit;
use std::ops::{Deref, DerefMut};

use foreign_types::{ForeignTypeRef, Opaque};

use crate::core::{EventRef, PoolRef};
use crate::ffi::{self, ngx_connection_t, ngx_err_t};

/// Wrapper struct for an [`ngx_connection_t`] pointer
///
/// There's no owned counterpart, as modules should never create or own `ngx_connection_t`
///
/// [`ngx_connection_t`]: http://nginx.org/en/docs/dev/development_guide.html#connection
pub struct Connection(Opaque);

unsafe impl ForeignTypeRef for Connection {
type CType = ngx_connection_t;
}

impl AsRef<ngx_connection_t> for Connection {
fn as_ref(&self) -> &ngx_connection_t {
self.deref()
}
}

impl AsMut<ngx_connection_t> for Connection {
fn as_mut(&mut self) -> &mut ngx_connection_t {
self.deref_mut()
}
}

impl Deref for Connection {
type Target = ngx_connection_t;

fn deref(&self) -> &Self::Target {
unsafe { &*self.as_ptr() }
}
}

impl DerefMut for Connection {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.as_ptr() }
}
}

impl Connection {
/// Returns a configuration pool reference
pub fn pool(&mut self) -> &mut PoolRef {
debug_assert!(!self.pool.is_null());
unsafe { PoolRef::from_ptr_mut(self.pool) }
}

/// Returns a read event reference
pub fn read(&mut self) -> &mut EventRef {
debug_assert!(!self.read.is_null());
unsafe { EventRef::from_ptr_mut(self.read) }
}

/// Returns a write event reference
pub fn write(&mut self) -> &mut EventRef {
debug_assert!(!self.write.is_null());
unsafe { EventRef::from_ptr_mut(self.write) }
}

/// Check `connect` result
pub fn test_connect(&mut self) -> Result<(), ngx_err_t> {
#[cfg(ngx_feature = "have_kqueue")]
if unsafe { ffi::ngx_event_flags } & (ffi::NGX_USE_KQUEUE_EVENT as usize) != 0 {
if self.write().pending_eof() != 0 || self.read().pending_eof() != 0 {
let err = if self.write().pending_eof() != 0 {
self.write().kq_errno
} else {
self.read().kq_errno
};

self.error(err, c"kevent() reported that connect() failed");
return Err(err);
} else {
return Ok(());
}
}

let mut err: std::ffi::c_int = 0;
let mut len: libc::socklen_t = std::mem::size_of_val(&err) as _;

// BSDs and Linux return 0 and set a pending error in err
// Solaris returns -1 and sets errno
if unsafe {
libc::getsockopt(
self.fd,
libc::SOL_SOCKET as _,
libc::SO_ERROR as _,
std::ptr::addr_of_mut!(err).cast(),
&mut len,
) == -1
} {
err = errno::errno().0;
}

if err != 0 {
self.error(err, c"connect() failed");
Err(err)
} else {
Ok(())
}
}

/// Handle OS errors
pub fn error(&mut self, err: ngx_err_t, msg: &std::ffi::CStr) -> ffi::ngx_int_t {
unsafe { ffi::ngx_connection_error(self.as_ptr(), err, msg.as_ptr().cast_mut()) }
}

/// Receive data from the connection
pub fn recv(&mut self, buf: &mut [MaybeUninit<u8>]) -> isize {
// send and recv are always set
unsafe { self.recv.unwrap_unchecked()(self.as_ptr(), buf.as_mut_ptr().cast(), buf.len()) }
}

/// Send data to the connection
pub fn send(&mut self, buf: &[u8]) -> isize {
// send and recv are always set
unsafe { self.send.unwrap_unchecked()(self.as_ptr(), buf.as_ptr().cast_mut(), buf.len()) }
}

/// Shutdown the connection
pub fn shutdown(&mut self, how: std::ffi::c_int) -> Result<(), ngx_err_t> {
if unsafe { libc::shutdown(self.fd, how) } == -1 {
return Err(errno::errno().0);
}
Ok(())
}

/// Close the connection
pub fn close(&mut self) {
unsafe { ffi::ngx_close_connection(self.as_ptr()) }
}
}
2 changes: 2 additions & 0 deletions src/core/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod array;
mod buffer;
mod conf_file;
mod connection;
mod event;
mod hash;
mod list;
Expand All @@ -11,6 +12,7 @@ mod string;
pub use array::*;
pub use buffer::*;
pub use conf_file::*;
pub use connection::*;
pub use event::*;
pub use hash::*;
pub use list::*;
Expand Down

0 comments on commit 24b41b1

Please sign in to comment.