Skip to content

Commit

Permalink
feat: add mdns devices discovery (#54)
Browse files Browse the repository at this point in the history
* feat: add mdns devices discovery

---------

Co-authored-by: Jinke <164604729+JinkeJ@users.noreply.github.com>
  • Loading branch information
cocool97 and JinkeJ authored Dec 1, 2024
1 parent b933ab0 commit 8c382f0
Show file tree
Hide file tree
Showing 30 changed files with 652 additions and 19 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/rust-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Build project
run: cargo build --release
run: cargo build --release --all-features
2 changes: 1 addition & 1 deletion .github/workflows/rust-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Run tests
run: cargo test --verbose
run: cargo test --verbose --all-features
2 changes: 1 addition & 1 deletion .github/workflows/rust-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
cargo install cargo-generate-rpm
- name: "build-release"
run: cargo build --release
run: cargo build --all-features --release

- name: "Build DEB package"
run: cargo deb -p adb_cli
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ homepage = "https://github.com/cocool97/adb_client"
keywords = ["adb", "android", "tcp", "usb"]
license = "MIT"
repository = "https://github.com/cocool97/adb_client"
version = "2.0.5"
version = "2.0.6"

# To build locally when working on a new release
[patch.crates-io]
Expand Down
15 changes: 15 additions & 0 deletions adb_cli/src/commands/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,19 @@ pub enum HostCommand {
Connect { address: SocketAddrV4 },
/// Disconnect device over WI-FI
Disconnect { address: SocketAddrV4 },
/// MDNS services
Mdns {
#[clap(subcommand)]
subcommand: MdnsCommand,
},
/// Display server status
ServerStatus,
}

#[derive(Parser, Debug)]
pub enum MdnsCommand {
/// Check mdns status
Check,
/// List mdns services available
Services,
}
2 changes: 1 addition & 1 deletion adb_cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod tcp;
mod usb;

pub use emu::EmuCommand;
pub use host::HostCommand;
pub use host::{HostCommand, MdnsCommand};
pub use local::LocalCommand;
pub use tcp::{TcpCommand, TcpCommands};
pub use usb::{UsbCommand, UsbCommands};
72 changes: 65 additions & 7 deletions adb_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,40 @@ mod models;

use adb_client::{
ADBDeviceExt, ADBEmulatorDevice, ADBServer, ADBTcpDevice, ADBUSBDevice, DeviceShort,
MDNSBackend, MDNSDiscoveryService,
};
use anyhow::{anyhow, Result};
use clap::Parser;
use commands::{EmuCommand, HostCommand, LocalCommand, TcpCommands, UsbCommands};
use commands::{EmuCommand, HostCommand, LocalCommand, MdnsCommand, TcpCommands, UsbCommands};
use models::{Command, Opts};
use std::fs::File;
use std::io::Write;
use std::path::Path;

fn main() -> Result<()> {
let opt = Opts::parse();
let opts = Opts::parse();

// RUST_LOG variable has more priority then "--debug" flag
if std::env::var("RUST_LOG").is_err() {
let level = match opts.debug {
true => "trace",
false => "info",
};

std::env::set_var("RUST_LOG", level);
}

// Setting default log level as "info" if not set
if std::env::var("RUST_LOG").is_err() {
std::env::set_var("RUST_LOG", "info");
}
env_logger::init();

match opt.command {
match opts.command {
Command::Local(local) => {
let mut adb_server = ADBServer::new(opt.address);
let mut adb_server = ADBServer::new(opts.address);

let mut device = match opt.serial {
let mut device = match opts.serial {
Some(serial) => adb_server.get_device_by_name(&serial)?,
None => adb_server.get_device()?,
};
Expand Down Expand Up @@ -104,7 +120,7 @@ fn main() -> Result<()> {
}
}
Command::Host(host) => {
let mut adb_server = ADBServer::new(opt.address);
let mut adb_server = ADBServer::new(opts.address);

match host {
HostCommand::Version => {
Expand Down Expand Up @@ -148,10 +164,35 @@ fn main() -> Result<()> {
adb_server.disconnect_device(address)?;
log::info!("Disconnected {address}");
}
HostCommand::Mdns { subcommand } => match subcommand {
MdnsCommand::Check => {
let check = adb_server.mdns_check()?;
let server_status = adb_server.server_status()?;
match server_status.mdns_backend {
MDNSBackend::Unknown => log::info!("unknown mdns backend..."),
MDNSBackend::Bonjour => match check {
true => log::info!("mdns daemon version [Bonjour]"),
false => log::info!("ERROR: mdns daemon unavailable"),
},
MDNSBackend::OpenScreen => {
log::info!("mdns daemon version [Openscreen discovery 0.0.0]")
}
}
}
MdnsCommand::Services => {
log::info!("List of discovered mdns services");
for service in adb_server.mdns_services()? {
log::info!("{}", service);
}
}
},
HostCommand::ServerStatus => {
log::info!("{}", adb_server.server_status()?);
}
}
}
Command::Emu(emu) => {
let mut emulator = match opt.serial {
let mut emulator = match opts.serial {
Some(serial) => ADBEmulatorDevice::new(serial, None)?,
None => return Err(anyhow!("Serial must be set to use emulators !")),
};
Expand Down Expand Up @@ -289,6 +330,23 @@ fn main() -> Result<()> {
}
}
}
Command::MdnsDiscovery => {
let mut service = MDNSDiscoveryService::new()?;

let (tx, rx) = std::sync::mpsc::channel();
service.start(tx)?;

log::info!("Starting mdns discovery...");
while let Ok(device) = rx.recv() {
log::info!(
"Found device {} with addresses {:?}",
device.fullname,
device.addresses
)
}

service.shutdown()?;
}
}

Ok(())
Expand Down
4 changes: 4 additions & 0 deletions adb_cli/src/models/opts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use crate::commands::{EmuCommand, HostCommand, LocalCommand, TcpCommand, UsbComm
#[derive(Parser, Debug)]
#[clap(about, version, author)]
pub struct Opts {
#[clap(long = "debug")]
pub debug: bool,
#[clap(short = 'a', long = "address", default_value = "127.0.0.1:5037")]
pub address: SocketAddrV4,
/// Serial id of a specific device. Every request will be sent to this device.
Expand All @@ -29,4 +31,6 @@ pub enum Command {
Usb(UsbCommand),
/// Device commands via TCP, no server needed
Tcp(TcpCommand),
/// Discover devices over MDNS without using adb-server
MdnsDiscovery,
}
5 changes: 4 additions & 1 deletion adb_client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ byteorder = { version = "1.5.0" }
chrono = { version = "0.4.38" }
homedir = { version = "0.3.4" }
image = { version = "0.25.5" }
log = { version = "0.4.22", features = ["max_level_debug", "release_max_level_debug"]}
lazy_static = { version = "1.5.0" }
log = { version = "0.4.22" }
mdns-sd = { version = "0.12.0" }
num-bigint = { version = "0.8.4", package = "num-bigint-dig" }
num-traits = { version = "0.2.19" }
quick-protobuf = { version = "0.8.1" }
rand = { version = "0.8.5" }
rcgen = { version = "0.13.1" }
regex = { version = "1.11.0", features = ["perf", "std", "unicode"] }
Expand Down
6 changes: 6 additions & 0 deletions adb_client/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ pub enum RustADBError {
/// Cannot upgrade connection from TCP to TLS
#[error("upgrade error: {0}")]
UpgradeError(String),
/// An error occurred while getting mdns devices
#[error(transparent)]
MDNSError(#[from] mdns_sd::Error),
/// An error occurred while sending data to channel
#[error(transparent)]
SendError(#[from] std::sync::mpsc::SendError<crate::MDNSDevice>),
}

impl<T> From<std::sync::PoisonError<T>> for RustADBError {
Expand Down
6 changes: 5 additions & 1 deletion adb_client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod constants;
mod device;
mod emulator_device;
mod error;
mod mdns;
mod models;
mod server;
mod server_device;
Expand All @@ -19,7 +20,10 @@ pub use adb_device_ext::ADBDeviceExt;
pub use device::{ADBTcpDevice, ADBUSBDevice};
pub use emulator_device::ADBEmulatorDevice;
pub use error::{Result, RustADBError};
pub use models::{AdbStatResponse, AdbVersion, DeviceLong, DeviceShort, DeviceState, RebootType};
pub use mdns::*;
pub use models::{
AdbStatResponse, AdbVersion, DeviceLong, DeviceShort, DeviceState, MDNSBackend, RebootType,
};
pub use server::*;
pub use server_device::ADBServerDevice;
pub use transports::*;
19 changes: 19 additions & 0 deletions adb_client/src/mdns/mdns_device.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use std::{collections::HashSet, net::IpAddr};

/// Represent a device found from mdns search
#[derive(Debug)]
pub struct MDNSDevice {
/// Full device address when resolved
pub fullname: String,
/// Device IP addresses
pub addresses: HashSet<IpAddr>,
}

impl From<mdns_sd::ServiceInfo> for MDNSDevice {
fn from(value: mdns_sd::ServiceInfo) -> Self {
Self {
fullname: value.get_fullname().to_string(),
addresses: value.get_addresses().to_owned(),
}
}
}
73 changes: 73 additions & 0 deletions adb_client/src/mdns/mdns_discovery.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use mdns_sd::{ServiceDaemon, ServiceEvent};
use std::{sync::mpsc::Sender, thread::JoinHandle};

use crate::{MDNSDevice, Result, RustADBError};

const ADB_SERVICE_NAME: &str = "_adb-tls-connect._tcp.local.";

/// Structure holding responsibility over mdns discovery
pub struct MDNSDiscoveryService {
daemon: ServiceDaemon,
thread_handle: Option<JoinHandle<Result<()>>>,
}

impl std::fmt::Debug for MDNSDiscoveryService {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MDNSDiscoveryService")
.field("daemon", &self.daemon.get_metrics())
.field("handle", &self.thread_handle)
.finish()
}
}

impl MDNSDiscoveryService {
/// Instantiate a new discovery service to find devices over mdns
pub fn new() -> Result<Self> {
Ok(MDNSDiscoveryService {
daemon: ServiceDaemon::new()?,
thread_handle: None,
})
}

/// Start discovery by spawning a new thread responsible of getting events.
pub fn start(&mut self, sender: Sender<MDNSDevice>) -> Result<()> {
let receiver = self.daemon.browse(ADB_SERVICE_NAME)?;

let handle: JoinHandle<Result<()>> = std::thread::spawn(move || loop {
while let Ok(event) = receiver.recv() {
match event {
ServiceEvent::SearchStarted(_)
| ServiceEvent::ServiceRemoved(_, _)
| ServiceEvent::ServiceFound(_, _)
| ServiceEvent::SearchStopped(_) => {
// Ignoring these events. We are only interesting in found devices
continue;
}
ServiceEvent::ServiceResolved(service_info) => {
if let Err(e) = sender.send(MDNSDevice::from(service_info)) {
return Err(e.into());
}
}
}
}
});

self.thread_handle = Some(handle);

Ok(())
}

/// Shutdown discovery engines.
pub fn shutdown(&mut self) -> Result<()> {
match self.daemon.shutdown() {
Ok(_) => Ok(()),
Err(e) => match e {
mdns_sd::Error::Again => {
self.daemon.shutdown()?;
Ok(())
}
e => Err(RustADBError::MDNSError(e)),
},
}
}
}
5 changes: 5 additions & 0 deletions adb_client/src/mdns/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mod mdns_device;
mod mdns_discovery;

pub use mdns_device::MDNSDevice;
pub use mdns_discovery::MDNSDiscoveryService;
26 changes: 23 additions & 3 deletions adb_client/src/models/adb_server_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,24 @@ pub(crate) enum AdbServerCommand {
Pair(SocketAddrV4, String),
TransportAny,
TransportSerial(String),
MDNSCheck,
MDNSServices,
ServerStatus,
ReconnectOffline,
Install(u64),
// Local commands
ShellCommand(String),
Shell,
FrameBuffer,
Sync,
Reboot(RebootType),
Forward(String, String, String),
Forward(String, String),
ForwardRemoveAll,
Reverse(String, String),
ReverseRemoveAll,
Reconnect,
TcpIp(u16),
Usb,
}

impl Display for AdbServerCommand {
Expand Down Expand Up @@ -56,12 +65,23 @@ impl Display for AdbServerCommand {
write!(f, "host:pair:{code}:{addr}")
}
AdbServerCommand::FrameBuffer => write!(f, "framebuffer:"),
AdbServerCommand::Forward(serial, remote, local) => {
write!(f, "host-serial:{serial}:forward:{local};{remote}")
AdbServerCommand::Forward(remote, local) => {
write!(f, "host:forward:{local};{remote}")
}
AdbServerCommand::ForwardRemoveAll => write!(f, "host:killforward-all"),
AdbServerCommand::Reverse(remote, local) => {
write!(f, "reverse:forward:{remote};{local}")
}
AdbServerCommand::ReverseRemoveAll => write!(f, "reverse:killforward-all"),
AdbServerCommand::MDNSCheck => write!(f, "host:mdns:check"),
AdbServerCommand::MDNSServices => write!(f, "host:mdns:services"),
AdbServerCommand::ServerStatus => write!(f, "host:server-status"),
AdbServerCommand::Reconnect => write!(f, "reconnect"),
AdbServerCommand::ReconnectOffline => write!(f, "host:reconnect-offline"),
AdbServerCommand::TcpIp(port) => {
write!(f, "tcpip:{port}")
}
AdbServerCommand::Usb => write!(f, "usb:"),
AdbServerCommand::Install(size) => write!(f, "exec:cmd package 'install' -S {size}"),
}
}
Expand Down
Loading

0 comments on commit 8c382f0

Please sign in to comment.