Skip to content

Commit

Permalink
Merge pull request #44 from windy1/feature/windows-support
Browse files Browse the repository at this point in the history
Windows support (cont.)
  • Loading branch information
windy1 authored Jan 21, 2024
2 parents 850c028 + 9b06a1c commit cd06af5
Show file tree
Hide file tree
Showing 34 changed files with 162 additions and 30 deletions.
23 changes: 21 additions & 2 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
macOS:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Prepare
run: rustup component add clippy
- name: Build
Expand All @@ -28,7 +28,7 @@ jobs:
linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Prepare
run: "rustup component add clippy && sudo apt -y install avahi-daemon libavahi-client-dev && sudo systemctl start avahi-daemon.service"
- name: Build
Expand All @@ -39,3 +39,22 @@ jobs:
run: ./scripts/lintall.sh
- name: Run tests
run: cargo test --verbose

windows-latest:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Install Bonjour
run: choco install -y bonjour
- name: Prepare
run: "rustup component add clippy"
- name: Build
shell: pwsh
run: ./scripts/buildall.ps1
- name: Check formatting
run: ./scripts/checkfmt.ps1
- name: Run clippy
shell: pwsh
run: ./scripts/lintall.ps1
- name: Run tests
run: cargo test --verbose
4 changes: 2 additions & 2 deletions Cargo.lock

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

5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ On Linux:
$ sudo apt install xorg-dev libxcb-shape0-dev libxcb-xfixes0-dev clang avahi-daemon libavahi-client-dev
```

On Windows:

Bonjour must be installed. It comes bundled with [iTunes](https://support.apple.com/en-us/HT210384) or [Bonjour Print Services](https://support.apple.com/kb/dl999). Further redistribution & bundling details are available on the [Apple Developer Site](https://developer.apple.com/licensing-trademarks/bonjour/).

## TODO

* Windows support
* You tell me...

# Examples
Expand Down
4 changes: 2 additions & 2 deletions examples/Cargo.lock

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

8 changes: 8 additions & 0 deletions scripts/buildall.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Set-PSDebug -Trace 1

cargo build --workspace --verbose
if ($LASTEXITCODE -ne 0) { Exit $LASTEXITCODE }

cd examples
cargo build --workspace --verbose
if ($LASTEXITCODE -ne 0) { Exit $LASTEXITCODE }
10 changes: 10 additions & 0 deletions scripts/checkfmt.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
$rs_files = Get-ChildItem "examples/browser/src","examples/service/src","zeroconf/src","zeroconf-macros/src" -Recurse -Filter *.rs

$exit_code = 0
foreach ($file in $rs_files)
{
Write-Host $file.FullName
rustfmt --check --verbose $file.FullName
if ($LASTEXITCODE -ne 0) { $exit_code = -1; }
}
Exit $exit_code
16 changes: 16 additions & 0 deletions scripts/lintall.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Set-PSDebug -Trace 1

$exit_code = 0

cargo clippy -- -D warnings
if ($LASTEXITCODE -ne 0) { $exit_code = -1; }
cargo clippy --all-targets --all-features -- -D warnings
if ($LASTEXITCODE -ne 0) { $exit_code = -1; }

cd examples
cargo clippy -- -D warnings
if ($LASTEXITCODE -ne 0) { $exit_code = -1; }
cargo clippy --all-targets --all-features -- -D warnings
if ($LASTEXITCODE -ne 0) { $exit_code = -1; }

Exit $exit_code
4 changes: 4 additions & 0 deletions scripts/verify.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
powershell.exe ./scripts/buildall.ps1
powershell.exe ./scripts/checkfmt.ps1
powershell.exe ./scripts/lintall.ps1
cargo test
6 changes: 5 additions & 1 deletion zeroconf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ categories = [
"os",
"os::linux-apis",
"os::macos-apis",
"os::windows-apis",
]
documentation = "https://docs.rs/zeroconf"

Expand All @@ -37,7 +38,10 @@ clap = { version = "4.4.4", features = ["derive"] }
avahi-sys = "0.10.0"

[target.'cfg(target_vendor = "apple")'.dependencies]
bonjour-sys = "0.1.1"
bonjour-sys = "0.2.0"

[target.'cfg(target_vendor = "pc")'.dependencies]
bonjour-sys = "0.2.0"

[package.metadata.docs.rs]
default-target = "x86_64-unknown-linux-gnu"
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
use std::rc::Rc;

use super::{client::ManagedAvahiClient, string_list::ManagedAvahiStringList};
use crate::avahi::avahi_util;
use crate::ffi::UnwrapMutOrNull;
use crate::linux::avahi_util;
use crate::Result;
use avahi_sys::{
avahi_client_errno, avahi_entry_group_add_service_strlst,
Expand Down
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion zeroconf/src/linux/poll.rs → zeroconf/src/avahi/poll.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Rust friendly `AvahiSimplePoll` wrappers/helpers
use crate::Result;
use crate::{error::Error, linux::avahi_util};
use crate::{avahi::avahi_util, error::Error};
use avahi_sys::{
avahi_simple_poll_free, avahi_simple_poll_iterate, avahi_simple_poll_loop,
avahi_simple_poll_new, AvahiSimplePoll,
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ use crate::ffi::{c_str, AsRaw, FromRaw};
use crate::prelude::*;
use crate::{EventLoop, NetworkInterface, Result, ServiceType, TxtRecord};
use crate::{ServiceDiscoveredCallback, ServiceDiscovery};
#[cfg(target_vendor = "pc")]
use bonjour_sys::sockaddr_in;
use bonjour_sys::{DNSServiceErrorType, DNSServiceFlags, DNSServiceRef};
use libc::{c_char, c_uchar, c_void, sockaddr_in};
#[cfg(target_vendor = "apple")]
use libc::sockaddr_in;
use libc::{c_char, c_uchar, c_void};
use std::any::Any;
use std::ffi::CString;
use std::fmt::{self, Formatter};
Expand Down Expand Up @@ -257,13 +261,23 @@ unsafe fn handle_get_address_info(
let port: u16 = ctx.resolved_port.to_be();

// on macOS the bytes are swapped for the ip
#[cfg(target_vendor = "apple")]
let ip = {
let address = address as *const sockaddr_in;
assert_not_null!(address);
let s_addr = (*address).sin_addr.s_addr.to_le_bytes();
IpAddr::from(s_addr).to_string()
};

#[cfg(target_vendor = "pc")]
let ip = {
let address = address as *const sockaddr_in;
assert_not_null!(address);
let s_un = (*address).sin_addr.S_un.S_un_b;
let s_addr = [s_un.s_b1, s_un.s_b2, s_un.s_b3, s_un.s_b4];
IpAddr::from(s_addr).to_string()
};

let hostname = c_str::copy_raw(hostname);
let domain = bonjour_util::normalize_domain(&ctx.resolved_domain.take().unwrap());
let kind = bonjour_util::normalize_domain(&ctx.resolved_kind.take().unwrap());
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl<'a> TEventLoop for BonjourEventLoop<'a> {
/// new data, the blocking call is not made.
fn poll(&self, timeout: Duration) -> Result<()> {
let service = self.service.lock().unwrap();
let select = unsafe { ffi::macos::read_select(service.sock_fd(), timeout)? };
let select = unsafe { ffi::bonjour::read_select(service.sock_fd(), timeout)? };
if select > 0 {
service.process_result()
} else {
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Low level interface for interacting with `DNSserviceRef`
use crate::{macos::bonjour_util, Result};
use crate::{bonjour::bonjour_util, Result};
use bonjour_sys::{
DNSServiceBrowse, DNSServiceBrowseReply, DNSServiceFlags, DNSServiceGetAddrInfo,
DNSServiceGetAddrInfoReply, DNSServiceProcessResult, DNSServiceProtocol, DNSServiceRef,
Expand Down Expand Up @@ -177,9 +177,18 @@ impl ManagedDNSServiceRef {
/// Delegate function for [`DNSServiceRefSockFD`].
///
/// [`DNSServiceRefSockFD`]: https://developer.apple.com/documentation/dnssd/1804698-dnsservicerefsockfd?language=objc
#[cfg(target_vendor = "apple")]
pub fn sock_fd(&self) -> i32 {
unsafe { DNSServiceRefSockFD(self.0) }
}

/// Delegate function for [`DNSServiceRefSockFD`].
///
/// [`DNSServiceRefSockFD`]: https://developer.apple.com/documentation/dnssd/1804698-dnsservicerefsockfd?language=objc
#[cfg(target_vendor = "pc")]
pub fn sock_fd(&self) -> u64 {
unsafe { DNSServiceRefSockFD(self.0) }
}
}

impl Default for ManagedDNSServiceRef {
Expand Down
File renamed without changes.
File renamed without changes.
44 changes: 43 additions & 1 deletion zeroconf/src/ffi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl<T> UnwrapMutOrNull<T> for Option<*mut T> {
}

#[cfg(target_vendor = "apple")]
pub(crate) mod macos {
pub(crate) mod bonjour {
use crate::Result;
use libc::{fd_set, suseconds_t, time_t, timeval};
use std::time::Duration;
Expand Down Expand Up @@ -100,3 +100,45 @@ pub(crate) mod macos {
}
}
}

#[cfg(target_vendor = "pc")]
pub(crate) mod bonjour {
use crate::Result;
use bonjour_sys::{fd_set, select, timeval};
#[cfg(target_vendor = "apple")]
use std::mem;
use std::ptr;
use std::time::Duration;

/// 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: u64, timeout: Duration) -> Result<u32> {
if timeout.as_secs() > i32::MAX as u64 {
return Err(
"Invalid timeout duration, as_secs() value exceeds ::libc::c_long. ".into(),
);
}

let timeout: timeval = timeval {
tv_sec: timeout.as_secs() as ::libc::c_long,
tv_usec: timeout.subsec_micros() as ::libc::c_long,
};

let mut set: fd_set = fd_set {
fd_count: 1,
fd_array: [0; 64],
};
set.fd_array[0] = sock_fd;

let result = select(0, &mut set, ptr::null_mut(), &mut set, &timeout);

if result < 0 {
Err("select(): returned error status".into())
} else {
Ok(result as u32)
}
}
}
32 changes: 16 additions & 16 deletions zeroconf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ extern crate derive_builder;
extern crate zeroconf_macros;
#[cfg(target_os = "linux")]
extern crate avahi_sys;
#[cfg(target_vendor = "apple")]
#[cfg(any(target_vendor = "apple", target_vendor = "pc"))]
extern crate bonjour_sys;
#[macro_use]
extern crate derive_getters;
Expand Down Expand Up @@ -217,9 +217,9 @@ pub mod service;
pub mod txt_record;

#[cfg(target_os = "linux")]
pub mod linux;
#[cfg(target_vendor = "apple")]
pub mod macos;
pub mod avahi;
#[cfg(any(target_vendor = "apple", target_vendor = "pc"))]
pub mod bonjour;

pub use browser::{ServiceDiscoveredCallback, ServiceDiscovery};
pub use interface::*;
Expand All @@ -228,33 +228,33 @@ pub use service_type::*;

/// Type alias for the platform-specific mDNS browser implementation
#[cfg(target_os = "linux")]
pub type MdnsBrowser = linux::browser::AvahiMdnsBrowser;
pub type MdnsBrowser = avahi::browser::AvahiMdnsBrowser;
/// Type alias for the platform-specific mDNS browser implementation
#[cfg(target_vendor = "apple")]
pub type MdnsBrowser = macos::browser::BonjourMdnsBrowser;
#[cfg(any(target_vendor = "apple", target_vendor = "pc"))]
pub type MdnsBrowser = bonjour::browser::BonjourMdnsBrowser;

/// Type alias for the platform-specific mDNS service implementation
#[cfg(target_os = "linux")]
pub type MdnsService = linux::service::AvahiMdnsService;
pub type MdnsService = avahi::service::AvahiMdnsService;
/// Type alias for the platform-specific mDNS service implementation
#[cfg(target_vendor = "apple")]
pub type MdnsService = macos::service::BonjourMdnsService;
#[cfg(any(target_vendor = "apple", target_vendor = "pc"))]
pub type MdnsService = bonjour::service::BonjourMdnsService;

/// Type alias for the platform-specific structure responsible for polling the mDNS event loop
#[cfg(target_os = "linux")]
pub type EventLoop<'a> = linux::event_loop::AvahiEventLoop<'a>;
pub type EventLoop<'a> = avahi::event_loop::AvahiEventLoop<'a>;
/// Type alias for the platform-specific structure responsible for polling the mDNS event loop
#[cfg(target_vendor = "apple")]
pub type EventLoop<'a> = macos::event_loop::BonjourEventLoop<'a>;
#[cfg(any(target_vendor = "apple", target_vendor = "pc"))]
pub type EventLoop<'a> = bonjour::event_loop::BonjourEventLoop<'a>;

/// Type alias for the platform-specific structure responsible for storing and accessing TXT
/// record data
#[cfg(target_os = "linux")]
pub type TxtRecord = linux::txt_record::AvahiTxtRecord;
pub type TxtRecord = avahi::txt_record::AvahiTxtRecord;
/// Type alias for the platform-specific structure responsible for storing and accessing TXT
/// record data
#[cfg(target_vendor = "apple")]
pub type TxtRecord = macos::txt_record::BonjourTxtRecord;
#[cfg(any(target_vendor = "apple", target_vendor = "pc"))]
pub type TxtRecord = bonjour::txt_record::BonjourTxtRecord;

/// Result type for this library
pub type Result<T> = std::result::Result<T, error::Error>;
2 changes: 2 additions & 0 deletions zeroconf/src/macros.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(useless_ptr_null_checks)]

macro_rules! assert_not_null {
($ptr:expr) => {
assert!(!$ptr.is_null(), "expected non-null value");
Expand Down
1 change: 1 addition & 0 deletions zeroconf/src/txt_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ mod tests {

let record = TxtRecord::new();

#[allow(clippy::never_loop)]
for (key, value) in record.iter() {
panic!("({:?}, {:?})", key, value);
}
Expand Down

0 comments on commit cd06af5

Please sign in to comment.