Merge pull request #15 from windy1/refactor/cleanup
Minor cleanup / refactoring
This commit is contained in:
commit
f24d94ae2d
20
.github/workflows/rust.yml
vendored
20
.github/workflows/rust.yml
vendored
@ -2,9 +2,9 @@ name: Rust
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [master]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master ]
|
branches: [master]
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CARGO_TERM_COLOR: always
|
CARGO_TERM_COLOR: always
|
||||||
@ -14,8 +14,14 @@ jobs:
|
|||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- name: Prepare
|
||||||
|
run: rustup component add clippy
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo build --verbose
|
run: ./scripts/buildall.sh
|
||||||
|
- name: Check formatting
|
||||||
|
run: ./scripts/checkfmt.sh
|
||||||
|
- name: Run clippy
|
||||||
|
run: ./scripts/lintall.sh
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cargo test --verbose
|
run: cargo test --verbose
|
||||||
|
|
||||||
@ -24,8 +30,12 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Prepare
|
- name: Prepare
|
||||||
run: "sudo apt -y install avahi-daemon libavahi-client-dev && sudo systemctl start avahi-daemon.service"
|
run: "rustup component add clippy && sudo apt -y install avahi-daemon libavahi-client-dev && sudo systemctl start avahi-daemon.service"
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo build --verbose
|
run: ./scripts/buildall.sh
|
||||||
|
- name: Check formatting
|
||||||
|
run: ./scripts/checkfmt.sh
|
||||||
|
- name: Run clippy
|
||||||
|
run: ./scripts/lintall.sh
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cargo test --verbose
|
run: cargo test --verbose
|
||||||
|
9
scripts/buildall.sh
Executable file
9
scripts/buildall.sh
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cargo build --workspace --verbose
|
||||||
|
(
|
||||||
|
cd examples
|
||||||
|
cargo build --workspace --verbose
|
||||||
|
)
|
5
scripts/checkfmt.sh
Executable file
5
scripts/checkfmt.sh
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
find examples/browser/src examples/service/src zeroconf/src zeroconf-macros/src -type f -name *.rs -print0 | xargs -0 -n1 rustfmt --check --verbose
|
11
scripts/lintall.sh
Executable file
11
scripts/lintall.sh
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cargo clippy -- -D warnings
|
||||||
|
cargo clippy --all-targets --all-features -- -D warnings
|
||||||
|
(
|
||||||
|
cd examples
|
||||||
|
cargo clippy -- -D warnings
|
||||||
|
cargo clippy --all-targets --all-features -- -D warnings
|
||||||
|
)
|
@ -1,13 +1,9 @@
|
|||||||
//! Utilities related to FFI bindings
|
//! Utilities related to FFI bindings
|
||||||
|
|
||||||
use crate::Result;
|
use libc::c_void;
|
||||||
#[cfg(target_os = "linux")]
|
use std::ptr;
|
||||||
use libc::{c_char, in_addr, sockaddr_in};
|
|
||||||
use libc::{c_void, fd_set, suseconds_t, time_t, timeval};
|
|
||||||
use std::time::Duration;
|
|
||||||
use std::{mem, ptr};
|
|
||||||
|
|
||||||
pub mod c_str;
|
pub(crate) mod c_str;
|
||||||
|
|
||||||
/// Helper trait to convert a raw `*mut c_void` to it's rust type
|
/// Helper trait to convert a raw `*mut c_void` to it's rust type
|
||||||
pub trait FromRaw<T> {
|
pub trait FromRaw<T> {
|
||||||
@ -43,36 +39,6 @@ pub trait AsRaw {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Performs a unix `select()` on the specified `sock_fd` and `timeout`. Returns the select result
|
|
||||||
/// or `Err` if the result is negative.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
/// This function is unsafe because it directly interfaces with C-library system calls.
|
|
||||||
pub unsafe fn read_select(sock_fd: i32, timeout: Duration) -> Result<u32> {
|
|
||||||
let mut read_flags: fd_set = mem::zeroed();
|
|
||||||
|
|
||||||
libc::FD_ZERO(&mut read_flags);
|
|
||||||
libc::FD_SET(sock_fd, &mut read_flags);
|
|
||||||
|
|
||||||
let tv_sec = timeout.as_secs() as time_t;
|
|
||||||
let tv_usec = timeout.subsec_micros() as suseconds_t;
|
|
||||||
let mut timeout = timeval { tv_sec, tv_usec };
|
|
||||||
|
|
||||||
let result = libc::select(
|
|
||||||
sock_fd + 1,
|
|
||||||
&mut read_flags,
|
|
||||||
ptr::null_mut(),
|
|
||||||
ptr::null_mut(),
|
|
||||||
&mut timeout,
|
|
||||||
);
|
|
||||||
|
|
||||||
if result < 0 {
|
|
||||||
Err("select(): returned error status".into())
|
|
||||||
} else {
|
|
||||||
Ok(result as u32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper trait to unwrap a type to a `*const T` or a null-pointer if not present.
|
/// Helper trait to unwrap a type to a `*const T` or a null-pointer if not present.
|
||||||
pub trait UnwrapOrNull<T> {
|
pub trait UnwrapOrNull<T> {
|
||||||
/// Unwraps this type to `*const T` or `ptr::null()` if not present.
|
/// Unwraps this type to `*const T` or `ptr::null()` if not present.
|
||||||
@ -97,18 +63,40 @@ impl<T> UnwrapMutOrNull<T> for Option<*mut T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a human-readable address of the specified raw address
|
#[cfg(target_vendor = "apple")]
|
||||||
///
|
pub(crate) mod macos {
|
||||||
/// # Safety
|
use crate::Result;
|
||||||
/// This function is unsafe because of calls to C-library system calls
|
use libc::{fd_set, suseconds_t, time_t, timeval};
|
||||||
#[cfg(target_os = "linux")]
|
use std::time::Duration;
|
||||||
pub unsafe fn get_ip(address: *const sockaddr_in) -> String {
|
use std::{mem, ptr};
|
||||||
assert_not_null!(address);
|
|
||||||
let raw = inet_ntoa(&(*address).sin_addr as *const in_addr);
|
|
||||||
String::from(c_str::raw_to_str(raw))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
/// Performs a unix `select()` on the specified `sock_fd` and `timeout`. Returns the select result
|
||||||
extern "C" {
|
/// or `Err` if the result is negative.
|
||||||
fn inet_ntoa(addr: *const in_addr) -> *const c_char;
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// This function is unsafe because it directly interfaces with C-library system calls.
|
||||||
|
pub unsafe fn read_select(sock_fd: i32, timeout: Duration) -> Result<u32> {
|
||||||
|
let mut read_flags: fd_set = mem::zeroed();
|
||||||
|
|
||||||
|
libc::FD_ZERO(&mut read_flags);
|
||||||
|
libc::FD_SET(sock_fd, &mut read_flags);
|
||||||
|
|
||||||
|
let tv_sec = timeout.as_secs() as time_t;
|
||||||
|
let tv_usec = timeout.subsec_micros() as suseconds_t;
|
||||||
|
let mut timeout = timeval { tv_sec, tv_usec };
|
||||||
|
|
||||||
|
let result = libc::select(
|
||||||
|
sock_fd + 1,
|
||||||
|
&mut read_flags,
|
||||||
|
ptr::null_mut(),
|
||||||
|
ptr::null_mut(),
|
||||||
|
&mut timeout,
|
||||||
|
);
|
||||||
|
|
||||||
|
if result < 0 {
|
||||||
|
Err("select(): returned error status".into())
|
||||||
|
} else {
|
||||||
|
Ok(result as u32)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,17 +133,17 @@ extern crate maplit;
|
|||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
mod ffi;
|
||||||
mod interface;
|
mod interface;
|
||||||
|
mod service_type;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
pub mod browser;
|
pub mod browser;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod event_loop;
|
pub mod event_loop;
|
||||||
pub mod ffi;
|
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
pub mod service;
|
pub mod service;
|
||||||
pub mod service_type;
|
|
||||||
pub mod txt_record;
|
pub mod txt_record;
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
//! Utilities related to Avahi
|
//! Utilities related to Avahi
|
||||||
|
|
||||||
use super::constants;
|
|
||||||
use crate::NetworkInterface;
|
use crate::NetworkInterface;
|
||||||
use avahi_sys::{avahi_address_snprint, avahi_strerror, AvahiAddress};
|
use avahi_sys::{avahi_address_snprint, avahi_strerror, AvahiAddress};
|
||||||
use libc::c_char;
|
use libc::c_char;
|
||||||
@ -16,11 +15,11 @@ use std::ffi::CStr;
|
|||||||
pub unsafe fn avahi_address_to_string(addr: *const AvahiAddress) -> String {
|
pub unsafe fn avahi_address_to_string(addr: *const AvahiAddress) -> String {
|
||||||
assert_not_null!(addr);
|
assert_not_null!(addr);
|
||||||
|
|
||||||
let addr_str = c_string!(alloc(constants::AVAHI_ADDRESS_STR_MAX));
|
let addr_str = c_string!(alloc(avahi_sys::AVAHI_ADDRESS_STR_MAX as usize));
|
||||||
|
|
||||||
avahi_address_snprint(
|
avahi_address_snprint(
|
||||||
addr_str.as_ptr() as *mut c_char,
|
addr_str.as_ptr() as *mut c_char,
|
||||||
constants::AVAHI_ADDRESS_STR_MAX,
|
avahi_sys::AVAHI_ADDRESS_STR_MAX as usize,
|
||||||
addr,
|
addr,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -43,7 +42,7 @@ pub fn get_error<'a>(code: i32) -> &'a str {
|
|||||||
/// [`NetworkInterface`]: ../../enum.NetworkInterface.html
|
/// [`NetworkInterface`]: ../../enum.NetworkInterface.html
|
||||||
pub fn interface_index(interface: NetworkInterface) -> i32 {
|
pub fn interface_index(interface: NetworkInterface) -> i32 {
|
||||||
match interface {
|
match interface {
|
||||||
NetworkInterface::Unspec => constants::AVAHI_IF_UNSPEC,
|
NetworkInterface::Unspec => avahi_sys::AVAHI_IF_UNSPEC,
|
||||||
NetworkInterface::AtIndex(i) => i as i32,
|
NetworkInterface::AtIndex(i) => i as i32,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
use super::avahi_util;
|
use super::avahi_util;
|
||||||
use super::client::{ManagedAvahiClient, ManagedAvahiClientParams};
|
use super::client::{ManagedAvahiClient, ManagedAvahiClientParams};
|
||||||
use super::constants;
|
|
||||||
use super::poll::ManagedAvahiSimplePoll;
|
use super::poll::ManagedAvahiSimplePoll;
|
||||||
use super::raw_browser::{ManagedAvahiServiceBrowser, ManagedAvahiServiceBrowserParams};
|
use super::raw_browser::{ManagedAvahiServiceBrowser, ManagedAvahiServiceBrowserParams};
|
||||||
use super::{
|
use super::{
|
||||||
@ -48,7 +47,7 @@ impl TMdnsBrowser for AvahiMdnsBrowser {
|
|||||||
browser: None,
|
browser: None,
|
||||||
kind: c_string!(service_type.to_string()),
|
kind: c_string!(service_type.to_string()),
|
||||||
context: Box::into_raw(Box::default()),
|
context: Box::into_raw(Box::default()),
|
||||||
interface_index: constants::AVAHI_IF_UNSPEC,
|
interface_index: avahi_sys::AVAHI_IF_UNSPEC,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,9 +85,9 @@ impl TMdnsBrowser for AvahiMdnsBrowser {
|
|||||||
|
|
||||||
self.browser = Some(ManagedAvahiServiceBrowser::new(
|
self.browser = Some(ManagedAvahiServiceBrowser::new(
|
||||||
ManagedAvahiServiceBrowserParams::builder()
|
ManagedAvahiServiceBrowserParams::builder()
|
||||||
.client(&(*self.context).client.as_ref().unwrap())
|
.client((*self.context).client.as_ref().unwrap())
|
||||||
.interface(self.interface_index)
|
.interface(self.interface_index)
|
||||||
.protocol(constants::AVAHI_PROTO_UNSPEC)
|
.protocol(avahi_sys::AVAHI_PROTO_UNSPEC)
|
||||||
.kind(self.kind.as_ptr())
|
.kind(self.kind.as_ptr())
|
||||||
.domain(ptr::null_mut())
|
.domain(ptr::null_mut())
|
||||||
.flags(0)
|
.flags(0)
|
||||||
@ -123,7 +122,7 @@ impl AvahiBrowserContext {
|
|||||||
if let Some(f) = &self.service_discovered_callback {
|
if let Some(f) = &self.service_discovered_callback {
|
||||||
f(result, self.user_context.clone());
|
f(result, self.user_context.clone());
|
||||||
} else {
|
} else {
|
||||||
warn!("attempted to invoke callback but none was set");
|
panic!("attempted to invoke browser callback but none was set");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,7 +190,7 @@ fn handle_browser_new(
|
|||||||
.name(name)
|
.name(name)
|
||||||
.kind(kind)
|
.kind(kind)
|
||||||
.domain(domain)
|
.domain(domain)
|
||||||
.aprotocol(constants::AVAHI_PROTO_UNSPEC)
|
.aprotocol(avahi_sys::AVAHI_PROTO_UNSPEC)
|
||||||
.flags(0)
|
.flags(0)
|
||||||
.callback(Some(resolve_callback))
|
.callback(Some(resolve_callback))
|
||||||
.userdata(raw_context)
|
.userdata(raw_context)
|
||||||
|
@ -15,7 +15,7 @@ use libc::{c_int, c_void};
|
|||||||
/// This struct allocates a new `*mut AvahiClient` when `ManagedAvahiClient::new()` is invoked and
|
/// This struct allocates a new `*mut AvahiClient` when `ManagedAvahiClient::new()` is invoked and
|
||||||
/// calls the Avahi function responsible for freeing the client on `trait Drop`.
|
/// calls the Avahi function responsible for freeing the client on `trait Drop`.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ManagedAvahiClient(pub(super) *mut AvahiClient);
|
pub struct ManagedAvahiClient(*mut AvahiClient);
|
||||||
|
|
||||||
impl ManagedAvahiClient {
|
impl ManagedAvahiClient {
|
||||||
/// Initializes the underlying `*mut AvahiClient` and verifies it was created; returning
|
/// Initializes the underlying `*mut AvahiClient` and verifies it was created; returning
|
||||||
@ -32,7 +32,7 @@ impl ManagedAvahiClient {
|
|||||||
|
|
||||||
let client = unsafe {
|
let client = unsafe {
|
||||||
avahi_client_new(
|
avahi_client_new(
|
||||||
avahi_simple_poll_get(poll.0),
|
avahi_simple_poll_get(poll.inner()),
|
||||||
flags,
|
flags,
|
||||||
callback,
|
callback,
|
||||||
userdata,
|
userdata,
|
||||||
@ -60,6 +60,10 @@ impl ManagedAvahiClient {
|
|||||||
pub fn host_name<'a>(&self) -> Result<&'a str> {
|
pub fn host_name<'a>(&self) -> Result<&'a str> {
|
||||||
unsafe { get_host_name(self.0) }
|
unsafe { get_host_name(self.0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn inner(&self) -> *mut AvahiClient {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for ManagedAvahiClient {
|
impl Drop for ManagedAvahiClient {
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
use avahi_sys::{AvahiIfIndex, AvahiProtocol};
|
|
||||||
|
|
||||||
pub const AVAHI_IF_UNSPEC: AvahiIfIndex = -1;
|
|
||||||
pub const AVAHI_PROTO_UNSPEC: AvahiProtocol = -1;
|
|
||||||
pub const AVAHI_ADDRESS_STR_MAX: usize = 40;
|
|
@ -72,7 +72,7 @@ impl ManagedAvahiEntryGroup {
|
|||||||
domain,
|
domain,
|
||||||
host,
|
host,
|
||||||
port,
|
port,
|
||||||
txt.map(|t| t.0).unwrap_mut_or_null()
|
txt.map(|t| t.inner()).unwrap_mut_or_null()
|
||||||
),
|
),
|
||||||
"could not register service"
|
"could not register service"
|
||||||
)?;
|
)?;
|
||||||
|
@ -6,8 +6,6 @@
|
|||||||
//! [Bonjour]: https://en.wikipedia.org/wiki/Bonjour_(software)
|
//! [Bonjour]: https://en.wikipedia.org/wiki/Bonjour_(software)
|
||||||
//! [Avahi]: https://en.wikipedia.org/wiki/Avahi_(software)
|
//! [Avahi]: https://en.wikipedia.org/wiki/Avahi_(software)
|
||||||
|
|
||||||
pub(crate) mod constants;
|
|
||||||
|
|
||||||
pub mod avahi_util;
|
pub mod avahi_util;
|
||||||
pub mod browser;
|
pub mod browser;
|
||||||
pub mod client;
|
pub mod client;
|
||||||
|
@ -11,7 +11,7 @@ use avahi_sys::{
|
|||||||
/// This struct allocates a new `*mut AvahiSimplePoll` when `ManagedAvahiClient::new()` is invoked
|
/// This struct allocates a new `*mut AvahiSimplePoll` when `ManagedAvahiClient::new()` is invoked
|
||||||
/// and calls the Avahi function responsible for freeing the poll on `trait Drop`.
|
/// and calls the Avahi function responsible for freeing the poll on `trait Drop`.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ManagedAvahiSimplePoll(pub(super) *mut AvahiSimplePoll);
|
pub struct ManagedAvahiSimplePoll(*mut AvahiSimplePoll);
|
||||||
|
|
||||||
impl ManagedAvahiSimplePoll {
|
impl ManagedAvahiSimplePoll {
|
||||||
/// Initializes the underlying `*mut AvahiSimplePoll` and verifies it was created; returning
|
/// Initializes the underlying `*mut AvahiSimplePoll` and verifies it was created; returning
|
||||||
@ -41,6 +41,10 @@ impl ManagedAvahiSimplePoll {
|
|||||||
pub fn iterate(&self, sleep_time: i32) {
|
pub fn iterate(&self, sleep_time: i32) {
|
||||||
unsafe { avahi_simple_poll_iterate(self.0, sleep_time) };
|
unsafe { avahi_simple_poll_iterate(self.0, sleep_time) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn inner(&self) -> *mut AvahiSimplePoll {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for ManagedAvahiSimplePoll {
|
impl Drop for ManagedAvahiSimplePoll {
|
||||||
|
@ -32,7 +32,14 @@ impl ManagedAvahiServiceBrowser {
|
|||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let browser = unsafe {
|
let browser = unsafe {
|
||||||
avahi_service_browser_new(
|
avahi_service_browser_new(
|
||||||
client.0, interface, protocol, kind, domain, flags, callback, userdata,
|
client.inner(),
|
||||||
|
interface,
|
||||||
|
protocol,
|
||||||
|
kind,
|
||||||
|
domain,
|
||||||
|
flags,
|
||||||
|
callback,
|
||||||
|
userdata,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,7 +36,15 @@ impl ManagedAvahiServiceResolver {
|
|||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let resolver = unsafe {
|
let resolver = unsafe {
|
||||||
avahi_service_resolver_new(
|
avahi_service_resolver_new(
|
||||||
client.0, interface, protocol, name, kind, domain, aprotocol, flags, callback,
|
client.inner(),
|
||||||
|
interface,
|
||||||
|
protocol,
|
||||||
|
name,
|
||||||
|
kind,
|
||||||
|
domain,
|
||||||
|
aprotocol,
|
||||||
|
flags,
|
||||||
|
callback,
|
||||||
userdata,
|
userdata,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
use super::avahi_util;
|
use super::avahi_util;
|
||||||
use super::client::{self, ManagedAvahiClient, ManagedAvahiClientParams};
|
use super::client::{self, ManagedAvahiClient, ManagedAvahiClientParams};
|
||||||
use super::constants;
|
|
||||||
use super::entry_group::{AddServiceParams, ManagedAvahiEntryGroup, ManagedAvahiEntryGroupParams};
|
use super::entry_group::{AddServiceParams, ManagedAvahiEntryGroup, ManagedAvahiEntryGroupParams};
|
||||||
use super::poll::ManagedAvahiSimplePoll;
|
use super::poll::ManagedAvahiSimplePoll;
|
||||||
use crate::ffi::{c_str, AsRaw, FromRaw, UnwrapOrNull};
|
use crate::ffi::{c_str, AsRaw, FromRaw, UnwrapOrNull};
|
||||||
@ -121,7 +120,7 @@ impl AvahiServiceContext {
|
|||||||
port,
|
port,
|
||||||
group: None,
|
group: None,
|
||||||
txt_record: None,
|
txt_record: None,
|
||||||
interface_index: constants::AVAHI_IF_UNSPEC,
|
interface_index: avahi_sys::AVAHI_IF_UNSPEC,
|
||||||
domain: None,
|
domain: None,
|
||||||
host: None,
|
host: None,
|
||||||
registered_callback: None,
|
registered_callback: None,
|
||||||
@ -133,7 +132,7 @@ impl AvahiServiceContext {
|
|||||||
if let Some(f) = &self.registered_callback {
|
if let Some(f) = &self.registered_callback {
|
||||||
f(result, self.user_context.clone());
|
f(result, self.user_context.clone());
|
||||||
} else {
|
} else {
|
||||||
warn!("attempted to invoke callback but none was set");
|
panic!("attempted to invoke service callback but none was set");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -203,7 +202,7 @@ unsafe fn create_service(
|
|||||||
group.add_service(
|
group.add_service(
|
||||||
AddServiceParams::builder()
|
AddServiceParams::builder()
|
||||||
.interface(context.interface_index)
|
.interface(context.interface_index)
|
||||||
.protocol(constants::AVAHI_PROTO_UNSPEC)
|
.protocol(avahi_sys::AVAHI_PROTO_UNSPEC)
|
||||||
.flags(0)
|
.flags(0)
|
||||||
.name(context.name.as_ref().unwrap().as_ptr())
|
.name(context.name.as_ref().unwrap().as_ptr())
|
||||||
.kind(context.kind.as_ptr())
|
.kind(context.kind.as_ptr())
|
||||||
|
@ -15,7 +15,7 @@ use std::ptr;
|
|||||||
///
|
///
|
||||||
/// `zeroconf::TxtRecord` provides the cross-platform bindings for this functionality.
|
/// `zeroconf::TxtRecord` provides the cross-platform bindings for this functionality.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ManagedAvahiStringList(pub(crate) *mut AvahiStringList);
|
pub struct ManagedAvahiStringList(*mut AvahiStringList);
|
||||||
|
|
||||||
impl ManagedAvahiStringList {
|
impl ManagedAvahiStringList {
|
||||||
/// Creates a new empty TXT record
|
/// Creates a new empty TXT record
|
||||||
@ -69,9 +69,13 @@ impl ManagedAvahiStringList {
|
|||||||
AvahiStringListNode::new(self.0)
|
AvahiStringListNode::new(self.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn clone_raw(raw: *mut AvahiStringList) -> Self {
|
pub(super) fn clone_raw(raw: *mut AvahiStringList) -> Self {
|
||||||
Self(unsafe { avahi_string_list_copy(raw) })
|
Self(unsafe { avahi_string_list_copy(raw) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn inner(&self) -> *mut AvahiStringList {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for ManagedAvahiStringList {
|
impl Clone for ManagedAvahiStringList {
|
||||||
|
@ -6,7 +6,6 @@ use crate::Result;
|
|||||||
use libc::c_char;
|
use libc::c_char;
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct AvahiTxtRecord(UnsafeCell<ManagedAvahiStringList>);
|
pub struct AvahiTxtRecord(UnsafeCell<ManagedAvahiStringList>);
|
||||||
|
|
||||||
impl TTxtRecord for AvahiTxtRecord {
|
impl TTxtRecord for AvahiTxtRecord {
|
||||||
|
@ -21,7 +21,7 @@ impl<'a> TEventLoop for BonjourEventLoop<'a> {
|
|||||||
/// new data, the blocking call is not made.
|
/// new data, the blocking call is not made.
|
||||||
fn poll(&self, timeout: Duration) -> Result<()> {
|
fn poll(&self, timeout: Duration) -> Result<()> {
|
||||||
let service = self.service.lock().unwrap();
|
let service = self.service.lock().unwrap();
|
||||||
let select = unsafe { ffi::read_select(service.sock_fd(), timeout)? };
|
let select = unsafe { ffi::macos::read_select(service.sock_fd(), timeout)? };
|
||||||
if select > 0 {
|
if select > 0 {
|
||||||
service.process_result()
|
service.process_result()
|
||||||
} else {
|
} else {
|
||||||
|
@ -80,13 +80,13 @@ impl TMdnsService for BonjourMdnsService {
|
|||||||
let txt_len = self
|
let txt_len = self
|
||||||
.txt_record
|
.txt_record
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|t| t.0.get_length())
|
.map(|t| t.inner().get_length())
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
|
|
||||||
let txt_record = self
|
let txt_record = self
|
||||||
.txt_record
|
.txt_record
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|t| t.0.get_bytes_ptr())
|
.map(|t| t.inner().get_bytes_ptr())
|
||||||
.unwrap_or_null();
|
.unwrap_or_null();
|
||||||
|
|
||||||
self.service.lock().unwrap().register_service(
|
self.service.lock().unwrap().register_service(
|
||||||
|
@ -9,8 +9,8 @@ use std::ffi::CString;
|
|||||||
use std::{mem, ptr};
|
use std::{mem, ptr};
|
||||||
|
|
||||||
/// Interface for interfacting with Bonjour's TXT record capabilities.
|
/// Interface for interfacting with Bonjour's TXT record capabilities.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Clone)]
|
||||||
pub struct BonjourTxtRecord(pub(crate) ManagedTXTRecordRef);
|
pub struct BonjourTxtRecord(ManagedTXTRecordRef);
|
||||||
|
|
||||||
impl TTxtRecord for BonjourTxtRecord {
|
impl TTxtRecord for BonjourTxtRecord {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
@ -76,6 +76,12 @@ impl TTxtRecord for BonjourTxtRecord {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BonjourTxtRecord {
|
||||||
|
pub(super) fn inner(&self) -> &ManagedTXTRecordRef {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<ManagedTXTRecordRef> for BonjourTxtRecord {
|
impl From<ManagedTXTRecordRef> for BonjourTxtRecord {
|
||||||
fn from(txt: ManagedTXTRecordRef) -> Self {
|
fn from(txt: ManagedTXTRecordRef) -> Self {
|
||||||
Self(txt)
|
Self(txt)
|
||||||
|
@ -36,9 +36,9 @@ impl ServiceType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_part(part: &str) -> Result<&str> {
|
fn check_part(part: &str) -> Result<&str> {
|
||||||
if part.contains(".") {
|
if part.contains('.') {
|
||||||
Err("invalid character: .".into())
|
Err("invalid character: .".into())
|
||||||
} else if part.contains(",") {
|
} else if part.contains(',') {
|
||||||
Err("invalid character: ,".into())
|
Err("invalid character: ,".into())
|
||||||
} else if part.is_empty() {
|
} else if part.is_empty() {
|
||||||
Err("cannot be empty".into())
|
Err("cannot be empty".into())
|
||||||
@ -48,8 +48,8 @@ impl ServiceType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn lstrip_underscore(s: &str) -> &str {
|
fn lstrip_underscore(s: &str) -> &str {
|
||||||
if s.starts_with("_") {
|
if let Some(stripped) = s.strip_prefix('_') {
|
||||||
&s[1..]
|
stripped
|
||||||
} else {
|
} else {
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
@ -75,12 +75,12 @@ impl FromStr for ServiceType {
|
|||||||
type Err = crate::error::Error;
|
type Err = crate::error::Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self> {
|
fn from_str(s: &str) -> Result<Self> {
|
||||||
let parts: Vec<&str> = s.split(",").collect();
|
let parts: Vec<&str> = s.split(',').collect();
|
||||||
if parts.is_empty() {
|
if parts.is_empty() {
|
||||||
return Err("could not parse ServiceType from string".into());
|
return Err("could not parse ServiceType from string".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let head: Vec<&str> = parts[0].split(".").collect();
|
let head: Vec<&str> = parts[0].split('.').collect();
|
||||||
if head.len() != 2 {
|
if head.len() != 2 {
|
||||||
return Err("invalid name and protocol".into());
|
return Err("invalid name and protocol".into());
|
||||||
}
|
}
|
||||||
@ -90,12 +90,12 @@ impl FromStr for ServiceType {
|
|||||||
|
|
||||||
let mut sub_types: Vec<&str> = vec![];
|
let mut sub_types: Vec<&str> = vec![];
|
||||||
if parts.len() > 1 {
|
if parts.len() > 1 {
|
||||||
for i in 1..parts.len() {
|
for part in parts.iter().skip(1) {
|
||||||
sub_types.push(Self::lstrip_underscore(parts[i]));
|
sub_types.push(Self::lstrip_underscore(part));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ServiceType::with_sub_types(name, protocol, sub_types)?)
|
ServiceType::with_sub_types(name, protocol, sub_types)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,17 +105,17 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn new_invalid() {
|
fn new_invalid() {
|
||||||
ServiceType::new(".http", "tcp").expect_err("invalid character: .".into());
|
ServiceType::new(".http", "tcp").expect_err("invalid character: .");
|
||||||
ServiceType::new("http", ".tcp").expect_err("invalid character: .".into());
|
ServiceType::new("http", ".tcp").expect_err("invalid character: .");
|
||||||
ServiceType::new(",http", "tcp").expect_err("invalid character: ,".into());
|
ServiceType::new(",http", "tcp").expect_err("invalid character: ,");
|
||||||
ServiceType::new("http", ",tcp").expect_err("invalid character: ,".into());
|
ServiceType::new("http", ",tcp").expect_err("invalid character: ,");
|
||||||
ServiceType::new("", "tcp").expect_err("cannot be empty".into());
|
ServiceType::new("", "tcp").expect_err("cannot be empty");
|
||||||
ServiceType::new("http", "").expect_err("cannot be empty".into());
|
ServiceType::new("http", "").expect_err("cannot be empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn must_have_name_and_protocol() {
|
fn must_have_name_and_protocol() {
|
||||||
ServiceType::from_str("_http").expect_err("invalid name and protocol".into());
|
ServiceType::from_str("_http").expect_err("invalid name and protocol");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -3,7 +3,7 @@ use std::sync::Once;
|
|||||||
static INIT: Once = Once::new();
|
static INIT: Once = Once::new();
|
||||||
|
|
||||||
pub(crate) fn setup() {
|
pub(crate) fn setup() {
|
||||||
INIT.call_once(|| env_logger::init());
|
INIT.call_once(env_logger::init);
|
||||||
}
|
}
|
||||||
|
|
||||||
mod service_test;
|
mod service_test;
|
||||||
|
@ -5,11 +5,11 @@ use serde::de::{MapAccess, Visitor};
|
|||||||
use serde::ser::SerializeMap;
|
use serde::ser::SerializeMap;
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt::{self, Debug};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
/// Interface for interacting with underlying mDNS implementation TXT record capabilities
|
/// Interface for interacting with underlying mDNS implementation TXT record capabilities
|
||||||
pub trait TTxtRecord: Clone + PartialEq + Eq {
|
pub trait TTxtRecord: Clone + PartialEq + Eq + Debug {
|
||||||
/// Constructs a new TXT record
|
/// Constructs a new TXT record
|
||||||
fn new() -> Self;
|
fn new() -> Self;
|
||||||
|
|
||||||
@ -130,6 +130,14 @@ impl<'de> Deserialize<'de> for TxtRecord {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Debug for TxtRecord {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("TxtRecord")
|
||||||
|
.field("data", &self.to_map())
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
Loading…
Reference in New Issue
Block a user