Skip to content

Commit

Permalink
feat(mdns): Add default and ffi build features
Browse files Browse the repository at this point in the history
  • Loading branch information
david-cermak committed Nov 27, 2024
1 parent b983fe4 commit 8f607c6
Show file tree
Hide file tree
Showing 11 changed files with 494 additions and 104 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/mdns__rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,7 @@ jobs:
cd components/mdns/examples/simple_query/
idf.py build
cd ../..
# FFI build
COMPILE_COMMANDS_DIR=examples/simple_query/build/ cargo run --example usage
# Default build
cargo run --example usage
1 change: 1 addition & 0 deletions components/mdns/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ if(${target} STREQUAL "linux")
set(dependencies esp_netif_linux esp_event)
set(private_dependencies esp_timer console esp_system)
set(srcs "mdns_stub.c" ${MDNS_NETWORKING} ${MDNS_CONSOLE})
# set(srcs "mdns.c" ${MDNS_NETWORKING} ${MDNS_CONSOLE})
else()
set(dependencies lwip console esp_netif)
set(private_dependencies esp_timer esp_wifi)
Expand Down
6 changes: 6 additions & 0 deletions components/mdns/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ edition = "2021"
[dependencies]
libc = "0.2"
dns-parser = "0.8"
socket2 = "*"
nix = "0.26"
lazy_static = "*"

[build-dependencies]
cc = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

[features]
ffi = []
17 changes: 15 additions & 2 deletions components/mdns/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,23 @@ struct CompileCommand {
}

fn main() {

println!("cargo:rerun-if-env-changed=COMPILE_COMMANDS_DIR");
// Get the directory for compile_commands.json from an environment variable
let compile_commands_dir = env::var("COMPILE_COMMANDS_DIR")
.unwrap_or_else(|_| ".".to_string()); // Default to current directory
let compile_commands_dir = match env::var("COMPILE_COMMANDS_DIR") {
Ok(dir) => dir,
Err(_) => {
// If the environment variable is not defined, return early
println!("COMPILE_COMMANDS_DIR not set, skipping custom build.");
// this is a native build
// println!("cargo:rustc-cfg=native");
return;
}
};

// building with FFI of mdns_networking
println!("COMPILE_COMMANDS_DIR set, enabling FFI feature.");
println!("cargo:rustc-cfg=feature=\"ffi\"");
// Construct the path to the compile_commands.json file
let compile_commands_path = Path::new(&compile_commands_dir).join("compile_commands.json");

Expand Down
25 changes: 17 additions & 8 deletions components/mdns/examples/usage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@
use mdns::*;
use std::thread;
use std::time::Duration;
use std::net::{UdpSocket, Ipv4Addr};
use socket2::{Socket, Domain, Type, Protocol};

pub fn test_mdns() {


fn test_mdns() {
let ip4 = EspIpAddr {
u_addr: EspIpUnion {
ip4: EspIp4Addr {
addr: u32::from_le_bytes([224, 0, 0, 251]), // Convert 224.0.0.251 to big-endian
addr: u32::from_le_bytes([224, 0, 0, 251]),
},
},
addr_type: ESP_IPADDR_TYPE_V4,
Expand All @@ -25,11 +29,13 @@ pub fn test_mdns() {
return;
}

let query_packet = create_mdns_query();
println!("{:?}", query_packet);
// let query_packet = create_mdns_query();
// println!("{:?}", query_packet);



let len = mdns_udp_pcb_write_rust(MdnsIf::Netif0, MdnsIpProtocol::Ip4, ip4, 5353, &query_packet);
println!("Bytes sent: {}", len);
// let len = mdns_udp_pcb_write_rust(MdnsIf::Netif0, MdnsIpProtocol::Ip4, ip4, 5353, &query_packet);
// println!("Bytes sent: {}", len);

thread::sleep(Duration::from_millis(500));

Expand All @@ -38,17 +44,20 @@ pub fn test_mdns() {
}
}


fn main() {
// Initialize mDNS
mdns::mdns_init();

// // Query for a specific host
// mdns::mdns_query_host_rust("example.local");

mdns::mdns_query("david-work.local");
thread::sleep(Duration::from_millis(500));
// Deinitialize mDNS
mdns::mdns_deinit();

test_mdns();

// test_mdns();

// let result = mdns::mdns_pcb_init_rust(mdns::MdnsIf::Netif0, mdns::MdnsIpProtocol::Ip4);
// match result {
Expand Down
4 changes: 2 additions & 2 deletions components/mdns/mdns.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ static inline esp_netif_t *esp_netif_from_preset_if(mdns_predef_if_t predef_if)
* @param tcpip_if Ordinal number of the interface
* @return Pointer ot the esp_netif object if the interface is available, NULL otherwise
*/
esp_netif_t *_mdns_get_esp_netif23(mdns_if_t tcpip_if)
esp_netif_t *_mdns_get_esp_netif(mdns_if_t tcpip_if)
{
if (tcpip_if < MDNS_MAX_INTERFACES) {
if (s_esp_netifs[tcpip_if].netif == NULL && s_esp_netifs[tcpip_if].predefined) {
Expand Down Expand Up @@ -347,7 +347,7 @@ static bool _mdns_can_add_more_services(void)
return true;
}

esp_err_t _mdns_send_rx_action23(mdns_rx_packet_t *packet)
esp_err_t _mdns_send_rx_action(mdns_rx_packet_t *packet)
{
mdns_action_t *action = NULL;

Expand Down
170 changes: 78 additions & 92 deletions components/mdns/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// src/lib.rs
mod service;
use service::{Service, NativeService, CService};

extern crate libc;
// extern crate trust_dns;
Expand All @@ -13,6 +15,29 @@ use std::fmt::Write; // For formatting strings
use std::net::Ipv4Addr;
use dns_parser::{Builder, QueryClass, QueryType, Packet};



#[cfg(not(feature = "ffi"))]
fn build_info() {
println!("Default build");
}

#[cfg(not(feature = "ffi"))]
fn create_service(cb: fn(&[u8])) -> Box<dyn Service> {
NativeService::init(cb)
}


#[cfg(feature = "ffi")]
fn build_info() {
println!("FFI build");
}

#[cfg(feature = "ffi")]
fn create_service(cb: fn(&[u8])) -> Box<dyn Service> {
CService::init(cb)
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct EspIp4Addr {
Expand Down Expand Up @@ -64,26 +89,6 @@ impl Clone for EspIpUnion {
// Manual implementation of Copy for the union
impl Copy for EspIpUnion {}

// // Other structs remain the same
// #[repr(C)]
// #[derive(Debug, Clone, Copy)]
// pub struct EspIp4Addr {
// addr: u32,
// }
//
// #[repr(C)]
// #[derive(Debug, Clone, Copy)]
// pub struct EspIp6Addr {
// addr: [u32; 4],
// zone: u8,
// }
//
// #[repr(C)]
// #[derive(Debug, Clone, Copy)]
// pub struct EspIpAddr {
// u_addr: EspIpUnion, // Union containing IPv4 or IPv6 address
// addr_type: u8,
// }
// Address type definitions
pub const ESP_IPADDR_TYPE_V4: u8 = 0;
pub const ESP_IPADDR_TYPE_V6: u8 = 6;
Expand Down Expand Up @@ -117,8 +122,6 @@ extern "C" {
) -> usize;
fn _mdns_pcb_deinit(tcpip_if: MdnsIf, ip_protocol: MdnsIpProtocol) -> EspErr;
fn set_callback(callback: extern "C" fn(*const u8, usize));

// fn set_callback2();
}

extern "C" fn rust_callback(data: *const u8, len: usize)
Expand All @@ -127,92 +130,92 @@ extern "C" fn rust_callback(data: *const u8, len: usize)
unsafe {
// Ensure that the data pointer is valid
if !data.is_null() {
// Create a Vec<u8> from the raw pointer and length
let data_vec = std::slice::from_raw_parts(data, len).to_vec();
// Create a Vec<u8> from the raw pointer and length
let data_vec = std::slice::from_raw_parts(data, len).to_vec();

// Now call the safe parser function with the Vec<u8>
parse_dns_response(&data_vec); }
// Now call the safe parser function with the Vec<u8>
parse_dns_response(&data_vec).unwrap();
}
}
}

fn parse_dns_response(data: &[u8]) {
// Safe handling of the slice
println!("Parsing DNS response with length: {}", data.len());

parse_dns_response2(data);
// Process the data (this will be safe, as `data` is a slice)
// Example: You could convert the slice to a string, inspect it, or pass it to a DNS library
}

fn parse_dns_response2(data: &[u8]) -> Result<(), String> {
fn parse_dns_response(data: &[u8]) -> Result<(), String> {
println!("Parsing DNS response with length 2 : {}", data.len());
// use dns_parser::Packet;
let packet = Packet::parse(&data).unwrap();
for answer in packet.answers {
println!("{:?}", answer);
}
// match Message::from_vec(data) {
// Ok(msg) => {
// // Successful parsing
// println!("Parsed DNS message successfully.");
// }
// Err(e) => {
// // Detailed error message
// eprintln!("Error parsing DNS message: {}", e);
// }
// }
// Parse the response message
// let msg = Message::from_vec(data).map_err(|e| e.to_string())?;
// println!("Type: {}", msg.op_code().to_string());
// // Check if the message is a response (opcode is Response)
// if msg.op_code() != trust_dns_client::op::OpCode::Status {
// return Err("Not a response message".to_string());
// }
//
// // Display the answer section (which should contain A record)
// for answer in msg.answers() {
// println!("Non-IP answer: {:?}", answer);
// if let Some(ipv4_addr) = answer.rdata().to_ip_addr() {
// println!("Resolved IP address: {}", ipv4_addr);
// } else {
// println!("Non-IP answer: {:?}", answer);
// }
// }

for question in packet.questions {
println!("{:?}", question);
}
Ok(())
}

use std::ffi::CString;
use std::thread;
use std::time::Duration;
use lazy_static::lazy_static;
use std::sync::{Arc, Mutex};

lazy_static! {
static ref SERVICE: Arc<Mutex<Option<Box<dyn Service>>>> = Arc::new(Mutex::new(None));
}

fn read_cb(vec: &[u8]) {
println!("Received {:?}", vec);
parse_dns_response(vec).unwrap();
}

pub fn mdns_init() {
build_info();
let mut service_guard = SERVICE.lock().unwrap();
if service_guard.is_none() {
// Initialize the service only if it hasn't been initialized
*service_guard = Some(create_service(read_cb));
}
// let service: Box<dyn Service> = create_service(read_cb);
// service.action1();
// let packet: [u8; 34] = [
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x64, 0x61,
// 0x76, 0x69, 0x64, 0x2d, 0x77, 0x6f, 0x72, 0x6b, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x00,
// 0x00, 0x01, 0x00, 0x01,
// ];
// service.send(packet.to_vec());
// thread::sleep(Duration::from_millis(500));
// service.deinit();
println!("mdns_init called");
}

pub fn mdns_deinit() {
let mut service_guard = SERVICE.lock().unwrap();
if let Some(service) = service_guard.take() {
service.deinit();
}
println!("mdns_deinit called");
}

pub fn create_mdns_query() -> Vec<u8> {
let query_name = "david-work.local"; // The domain you want to query
fn create_a_query(name: &str) -> Vec<u8> {
let query_type = QueryType::A; // Type A query for IPv4 address
let query_class = QueryClass::IN; // Class IN (Internet)

// Create a new query with ID and recursion setting
let mut builder = Builder::new_query(12345, true);
let mut builder = Builder::new_query(0x5555, true);

// Add the question for "david-work.local"
builder.add_question(query_name, false, query_type, query_class);
builder.add_question(name, false, query_type, query_class);

// Build and return the query packet
builder.build().unwrap_or_else(|x| x)
}

pub fn mdns_query_host_rust(name: &str) {
let c_name = CString::new(name).expect("Failed to create CString");
// unsafe {
// mdns_query_host(c_name.as_ptr());
// }
pub fn mdns_query(name: &str) {
let service_guard = SERVICE.lock().unwrap();
if let Some(service) = &*service_guard {
let packet = create_a_query(name);
service.send(packet);
} else {
println!("Service not initialized");
}
}

pub fn mdns_pcb_init_rust(tcpip_if: MdnsIf, ip_protocol: MdnsIpProtocol) -> Result<(), EspErr> {
Expand All @@ -229,24 +232,7 @@ pub fn mdns_pcb_init_rust(tcpip_if: MdnsIf, ip_protocol: MdnsIpProtocol) -> Resu
}
}

pub fn mdns_udp_pcb_write_rust(
tcpip_if: MdnsIf,
ip_protocol: MdnsIpProtocol,
ip: EspIpAddr,
port: u16,
data: &[u8],
) -> usize {
unsafe {
_mdns_udp_pcb_write(
tcpip_if,
ip_protocol,
&ip as *const EspIpAddr,
port,
data.as_ptr(),
data.len(),
)
}
}


pub fn mdns_pcb_deinit_rust(tcpip_if: MdnsIf, ip_protocol: MdnsIpProtocol) -> Result<(), EspErr> {
let err = unsafe { _mdns_pcb_deinit(tcpip_if, ip_protocol) };
Expand Down
Loading

0 comments on commit 8f607c6

Please sign in to comment.