dns_sd/
lib.rs

1extern crate libc;
2
3use std::ptr::null;
4use std::ptr::null_mut;
5use std::ffi::CString;
6
7mod ffi {
8    use libc::c_void;
9    use libc::c_char;
10
11    pub enum DNSService {}
12    pub type DNSServiceRef = *mut DNSService;
13
14    #[repr(i32)]
15    #[allow(dead_code)]
16    #[derive(Copy,Clone,Debug,PartialEq,Eq)]
17    pub enum DNSServiceErrorType {
18        NoError = 0,
19        Unknown = -65537,
20        NoSuchName = -65538,
21        NoMemory = -65539,
22        BadParam = -65540,
23        BadReference = -65541,
24        BadState = -65542,
25        BadFlags = -65543,
26        Unsupported = -65544,
27        NotInitialized = -65545,
28        AlreadyRegistered = -65547,
29        NameConflict = -65548,
30        Invalid = -65549,
31        Firewall = -65550,
32        Incompatible = -65551,
33        BadInterfaceIndex = -65552,
34        Refused = -65553,
35        NoSuchRecord = -65554,
36        NoAuth = -65555,
37        NoSuchKey = -65556,
38        NATTraversal = -65557,
39        DoubleNAT = -65558,
40        BadTime = -65559,
41        BadSig = -65560,
42        BadKey = -65561,
43        Transient = -65562,
44        ServiceNotRunning = -65563,
45        NATPortMappingUnsupported = -65564,
46        NATPortMappingDisabled = -65565,
47        NoRouter = -65566,
48        PollingMode = -65567,
49        Timeout = -65568,
50    }
51
52    pub type DNSServiceFlags = u32;
53    pub type DNSServiceRegisterReply = Option<extern "C" fn(DNSServiceRef,
54                                                            DNSServiceFlags,
55                                                            DNSServiceErrorType,
56                                                            *const c_char,
57                                                            *const c_char,
58                                                            *const c_char,
59                                                            *mut c_void)
60                                                           >;
61
62    extern "C" {
63        pub fn DNSServiceRegister(sdRef: *mut DNSServiceRef,
64                                  flags: DNSServiceFlags,
65                                  interfaceIndex: u32,
66                                  name: *const c_char,
67                                  regtype: *const c_char,
68                                  domain: *const c_char,
69                                  host: *const c_char,
70                                  port: u16,
71                                  txtLen: u16,
72                                  txtRecord: *const u8,
73                                  callBack: DNSServiceRegisterReply,
74                                  context: *mut c_void)
75                                  -> DNSServiceErrorType;
76
77        pub fn DNSServiceRefDeallocate(sdRef: DNSServiceRef);
78    }
79}
80
81#[derive(Debug)]
82pub struct DNSService {
83    sd_ref: ffi::DNSServiceRef,
84}
85
86#[derive(Debug)]
87pub struct DNSError(ffi::DNSServiceErrorType);
88
89impl std::fmt::Display for DNSError {
90    fn fmt(&self, format: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
91        write!(format, "DNS-SD Error: {:?}", self.0)
92    }
93}
94
95impl std::error::Error for DNSError {
96    fn description(&self) -> &str {
97        "DNS-SD Error"
98    }
99}
100
101impl DNSService {
102    pub fn register(name: Option<&str>,
103                    regtype: &str,
104                    domain: Option<&str>,
105                    host: Option<&str>,
106                    port: u16,
107                    txt: &[&str])
108                    -> std::result::Result<DNSService, DNSError> {
109        let mut sd_ref: ffi::DNSServiceRef = null_mut();
110
111        let txt_data: Vec<u8> = txt.into_iter()
112                                   .flat_map(|value| {
113                                       std::iter::once(value.len() as u8).chain(value.bytes())
114                                   })
115                                   .collect();
116
117        let name = name.map(|s| CString::new(s).unwrap());
118        let regtype = CString::new(regtype).unwrap();
119        let domain = domain.map(|s| CString::new(s).unwrap());
120        let host = host.map(|s| CString::new(s).unwrap());
121
122        let err = unsafe {
123            ffi::DNSServiceRegister(&mut sd_ref as *mut _,
124                                    0,
125                                    0,
126                                    name.as_ref().map_or(null(), |s| s.as_ptr()),
127                                    regtype.as_ptr(),
128                                    domain.as_ref().map_or(null(), |s| s.as_ptr()),
129                                    host.as_ref().map_or(null(), |s| s.as_ptr()),
130                                    port.to_be(),
131                                    txt_data.len() as u16,
132                                    if txt_data.is_empty() {
133                                        null()
134                                    } else {
135                                        txt_data.as_ptr()
136                                    },
137                                    None,
138                                    null_mut())
139        };
140
141        // We must be sure these stay are still alive during the DNSServiceRegister call
142        // Because we pass them as raw pointers, rust's borrow checker is useless there
143        // If they are still valid at this point, then we're good
144        drop(name);
145        drop(regtype);
146        drop(domain);
147        drop(host);
148        drop(txt_data);
149
150        if err == ffi::DNSServiceErrorType::NoError {
151            Ok(DNSService { sd_ref: sd_ref })
152        } else {
153            Err(DNSError(err))
154        }
155    }
156}
157
158impl Drop for DNSService {
159    fn drop(&mut self) {
160        unsafe {
161            ffi::DNSServiceRefDeallocate(self.sd_ref);
162        }
163    }
164}