Skip to content

Commit

Permalink
improve dubious AvahiClient initialization
Browse files Browse the repository at this point in the history
Signed-off-by: Walker Crouse <[email protected]>
  • Loading branch information
Walker Crouse authored and Walker Crouse committed Jan 28, 2024
1 parent 3004d35 commit 8c614ac
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 143 deletions.
126 changes: 64 additions & 62 deletions zeroconf/src/avahi/browser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,32 +32,29 @@ use std::{fmt, ptr};

#[derive(Debug)]
pub struct AvahiMdnsBrowser {
client: Option<Rc<ManagedAvahiClient>>,
poll: Option<Rc<ManagedAvahiSimplePoll>>,
browser: Option<ManagedAvahiServiceBrowser>,
kind: CString,
interface_index: AvahiIfIndex,
context: Box<AvahiBrowserContext>,
client: Option<ManagedAvahiClient>,
poll: Option<Rc<ManagedAvahiSimplePoll>>,
}

impl TMdnsBrowser for AvahiMdnsBrowser {
fn new(service_type: ServiceType) -> Self {
Self {
client: None,
poll: None,
browser: None,
kind: c_string!(avahi_util::format_browser_type(&service_type)),
context: Box::default(),
interface_index: avahi_sys::AVAHI_IF_UNSPEC,
context: Box::new(AvahiBrowserContext::new(
c_string!(avahi_util::format_browser_type(&service_type)),
avahi_sys::AVAHI_IF_UNSPEC,
)),
}
}

fn set_network_interface(&mut self, interface: NetworkInterface) {
self.interface_index = avahi_util::interface_index(interface);
self.context.interface_index = avahi_util::interface_index(interface);
}

fn network_interface(&self) -> NetworkInterface {
avahi_util::interface_from_index(self.interface_index)
avahi_util::interface_from_index(self.context.interface_index)
}

fn set_service_discovered_callback(
Expand All @@ -80,50 +77,41 @@ impl TMdnsBrowser for AvahiMdnsBrowser {

self.poll = Some(Rc::new(ManagedAvahiSimplePoll::new()?));

self.client = Some(Rc::new(ManagedAvahiClient::new(
self.client = Some(ManagedAvahiClient::new(
ManagedAvahiClientParams::builder()
.poll(Rc::clone(self.poll.as_ref().unwrap()))
.poll(self.poll.as_ref().unwrap().inner())
.flags(AvahiClientFlags(0))
.callback(Some(client_callback))
.userdata(ptr::null_mut())
.build()?,
)?));

self.context.client = self.client.clone();

self.browser = Some(ManagedAvahiServiceBrowser::new(
ManagedAvahiServiceBrowserParams::builder()
.interface(self.interface_index)
.protocol(avahi_sys::AVAHI_PROTO_UNSPEC)
.kind(self.kind.as_ptr())
.domain(ptr::null_mut())
.flags(0)
.callback(Some(browse_callback))
.userdata(self.context.as_raw())
.client(Rc::clone(self.context.client.as_ref().unwrap()))
.build()?,
)?);

Ok(EventLoop::new(self.poll.as_ref().unwrap().clone()))
}
}

impl Drop for AvahiMdnsBrowser {
fn drop(&mut self) {
// browser must be freed first
self.browser = None;
}
}

#[derive(FromRaw, AsRaw)]
struct AvahiBrowserContext {
client: Option<Rc<ManagedAvahiClient>>,
resolvers: ServiceResolverSet,
service_discovered_callback: Option<Box<ServiceDiscoveredCallback>>,
user_context: Option<Arc<dyn Any>>,
interface_index: AvahiIfIndex,
kind: CString,
browser: Option<ManagedAvahiServiceBrowser>,
}

impl AvahiBrowserContext {
fn new(kind: CString, interface_index: AvahiIfIndex) -> Self {
Self {
resolvers: ServiceResolverSet::default(),
service_discovered_callback: None,
user_context: None,
interface_index,
kind,
browser: None,
}
}

fn invoke_callback(&self, result: Result<ServiceDiscovery>) {
if let Some(f) = &self.service_discovered_callback {
f(result, self.user_context.clone());
Expand All @@ -133,27 +121,50 @@ impl AvahiBrowserContext {
}
}

#[allow(clippy::derivable_impls)]
impl Default for AvahiBrowserContext {
fn default() -> Self {
AvahiBrowserContext {
client: None,
resolvers: ServiceResolverSet::default(),
service_discovered_callback: None,
user_context: None,
}
}
}

impl fmt::Debug for AvahiBrowserContext {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("AvahiBrowserContext")
.field("client", &self.client)
.field("resolvers", &self.resolvers)
.finish()
}
}

unsafe extern "C" fn client_callback(
client: *mut AvahiClient,
state: AvahiClientState,
userdata: *mut c_void,
) {
match state {
avahi_sys::AvahiClientState_AVAHI_CLIENT_S_RUNNING => {
create_browser(client, AvahiBrowserContext::from_raw(userdata))
.unwrap_or_else(|e| panic!("failed to create browser: {}", e))
}
_ => {
// TODO: handle other states
}
}
}

unsafe fn create_browser(
client: *mut AvahiClient,
context: &mut AvahiBrowserContext,
) -> Result<()> {
context.browser = Some(ManagedAvahiServiceBrowser::new(
ManagedAvahiServiceBrowserParams::builder()
.interface(context.interface_index)
.protocol(avahi_sys::AVAHI_PROTO_UNSPEC)
.kind(context.kind.as_ptr())
.domain(ptr::null_mut())
.flags(0)
.callback(Some(browse_callback))
.userdata(context.as_raw())
.client(client)
.build()?,
)?);

Ok(())
}

unsafe extern "C" fn browse_callback(
_browser: *mut AvahiServiceBrowser,
interface: AvahiIfIndex,
Expand All @@ -180,7 +191,7 @@ unsafe extern "C" fn browse_callback(
};
}

fn handle_browser_new(
unsafe fn handle_browser_new(
context: &mut AvahiBrowserContext,
interface: AvahiIfIndex,
protocol: AvahiProtocol,
Expand All @@ -189,9 +200,10 @@ fn handle_browser_new(
domain: *const c_char,
) -> Result<()> {
let raw_context = context.as_raw();

context.resolvers.insert(ManagedAvahiServiceResolver::new(
ManagedAvahiServiceResolverParams::builder()
.client(Rc::clone(context.client.as_ref().unwrap()))
.client(context.browser.as_ref().unwrap().get_client())
.interface(interface)
.protocol(protocol)
.name(name)
Expand All @@ -203,6 +215,7 @@ fn handle_browser_new(
.userdata(raw_context)
.build()?,
)?);

Ok(())
}

Expand Down Expand Up @@ -293,14 +306,3 @@ unsafe fn handle_resolver_found(

Ok(())
}

extern "C" fn client_callback(
_client: *mut AvahiClient,
state: AvahiClientState,
_userdata: *mut c_void,
) {
// TODO: handle this better
if let avahi_sys::AvahiClientState_AVAHI_CLIENT_FAILURE = state {
panic!("client failure");
}
}
12 changes: 4 additions & 8 deletions zeroconf/src/avahi/client.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
//! Rust friendly `AvahiClient` wrappers/helpers
use std::rc::Rc;

use super::avahi_util;
use super::poll::ManagedAvahiSimplePoll;
use crate::ffi::c_str;
use crate::Result;
use avahi_sys::{
avahi_client_free, avahi_client_get_host_name, avahi_client_new, avahi_simple_poll_get,
AvahiClient, AvahiClientCallback, AvahiClientFlags,
AvahiClient, AvahiClientCallback, AvahiClientFlags, AvahiSimplePoll,
};
use libc::{c_int, c_void};

Expand All @@ -19,7 +16,6 @@ use libc::{c_int, c_void};
#[derive(Debug)]
pub struct ManagedAvahiClient {
pub(crate) inner: *mut AvahiClient,
_poll: Rc<ManagedAvahiSimplePoll>,
}

impl ManagedAvahiClient {
Expand All @@ -37,7 +33,7 @@ impl ManagedAvahiClient {

let inner = unsafe {
avahi_client_new(
avahi_simple_poll_get(poll.inner()),
avahi_simple_poll_get(poll),
flags,
callback,
userdata,
Expand All @@ -50,7 +46,7 @@ impl ManagedAvahiClient {
}

match err {
0 => Ok(Self { inner, _poll: poll }),
0 => Ok(Self { inner }),
_ => Err(format!(
"could not initialize AvahiClient: {}",
avahi_util::get_error(err)
Expand Down Expand Up @@ -80,7 +76,7 @@ impl Drop for ManagedAvahiClient {
/// [`avahi_client_new()`]: https://avahi.org/doxygen/html/client_8h.html#a07b2a33a3e7cbb18a0eb9d00eade6ae6
#[derive(Builder, BuilderDelegate)]
pub struct ManagedAvahiClientParams {
poll: Rc<ManagedAvahiSimplePoll>,
poll: *mut AvahiSimplePoll,
flags: AvahiClientFlags,
callback: AvahiClientCallback,
userdata: *mut c_void,
Expand Down
16 changes: 6 additions & 10 deletions zeroconf/src/avahi/entry_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use crate::Result;
use avahi_sys::{
avahi_client_errno, avahi_entry_group_add_service_strlst,
avahi_entry_group_add_service_subtype, avahi_entry_group_commit, avahi_entry_group_free,
avahi_entry_group_is_empty, avahi_entry_group_new, avahi_entry_group_reset, AvahiEntryGroup,
AvahiEntryGroupCallback, AvahiIfIndex, AvahiProtocol, AvahiPublishFlags,
avahi_entry_group_is_empty, avahi_entry_group_new, avahi_entry_group_reset, AvahiClient,
AvahiEntryGroup, AvahiEntryGroupCallback, AvahiIfIndex, AvahiProtocol, AvahiPublishFlags,
};
use libc::{c_char, c_void};

Expand All @@ -21,7 +21,6 @@ use libc::{c_char, c_void};
#[derive(Debug)]
pub struct ManagedAvahiEntryGroup {
inner: *mut AvahiEntryGroup,
_client: Rc<ManagedAvahiClient>,
}

impl ManagedAvahiEntryGroup {
Expand All @@ -34,16 +33,13 @@ impl ManagedAvahiEntryGroup {
userdata,
}: ManagedAvahiEntryGroupParams,
) -> Result<Self> {
let inner = unsafe { avahi_entry_group_new(client.inner, callback, userdata) };
let inner = unsafe { avahi_entry_group_new(client, callback, userdata) };

if inner.is_null() {
let err = avahi_util::get_error(unsafe { avahi_client_errno(client.inner) });
let err = avahi_util::get_error(unsafe { avahi_client_errno(client) });
Err(format!("could not initialize AvahiEntryGroup: {}", err).into())
} else {
Ok(Self {
inner,
_client: client,
})
Ok(Self { inner })
}
}

Expand Down Expand Up @@ -153,7 +149,7 @@ impl Drop for ManagedAvahiEntryGroup {
/// [avahi_entry_group_new()]: https://avahi.org/doxygen/html/publish_8h.html#abb17598f2b6ec3c3f69defdd488d568c
#[derive(Builder, BuilderDelegate)]
pub struct ManagedAvahiEntryGroupParams {
client: Rc<ManagedAvahiClient>,
client: *mut AvahiClient,
callback: AvahiEntryGroupCallback,
userdata: *mut c_void,
}
Expand Down
34 changes: 15 additions & 19 deletions zeroconf/src/avahi/raw_browser.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
//! Rust friendly `AvahiServiceBrowser` wrappers/helpers
use std::rc::Rc;

use super::client::ManagedAvahiClient;
use crate::Result;
use avahi_sys::{
avahi_service_browser_free, avahi_service_browser_new, AvahiIfIndex, AvahiLookupFlags,
AvahiProtocol, AvahiServiceBrowser, AvahiServiceBrowserCallback,
avahi_service_browser_free, avahi_service_browser_get_client, avahi_service_browser_new,
AvahiClient, AvahiIfIndex, AvahiLookupFlags, AvahiProtocol, AvahiServiceBrowser,
AvahiServiceBrowserCallback,
};
use libc::{c_char, c_void};

Expand All @@ -17,7 +15,6 @@ use libc::{c_char, c_void};
#[derive(Debug)]
pub struct ManagedAvahiServiceBrowser {
inner: *mut AvahiServiceBrowser,
_client: Rc<ManagedAvahiClient>,
}

impl ManagedAvahiServiceBrowser {
Expand All @@ -37,26 +34,25 @@ impl ManagedAvahiServiceBrowser {
) -> Result<Self> {
let inner = unsafe {
avahi_service_browser_new(
client.inner,
interface,
protocol,
kind,
domain,
flags,
callback,
userdata,
client, interface, protocol, kind, domain, flags, callback, userdata,
)
};

if inner.is_null() {
Err("could not initialize Avahi service browser".into())
} else {
Ok(Self {
inner,
_client: client,
})
Ok(Self { inner })
}
}

/// Returns the underlying `*mut AvahiServiceBrowser`.
///
/// # Safety
/// This function leaks the internal raw pointer, useful for accessing within callbacks where
/// you are sure the pointer is still valid.
pub unsafe fn get_client(&self) -> *mut AvahiClient {
avahi_service_browser_get_client(self.inner)
}
}

impl Drop for ManagedAvahiServiceBrowser {
Expand All @@ -73,7 +69,7 @@ impl Drop for ManagedAvahiServiceBrowser {
/// [`avahi_service_browser_new()`]: https://avahi.org/doxygen/html/lookup_8h.html#a52d55a5156a7943012d03e6700880d2b
#[derive(Builder, BuilderDelegate)]
pub struct ManagedAvahiServiceBrowserParams {
client: Rc<ManagedAvahiClient>,
client: *mut AvahiClient,
interface: AvahiIfIndex,
protocol: AvahiProtocol,
kind: *const c_char,
Expand Down
Loading

0 comments on commit 8c614ac

Please sign in to comment.