1#![cfg_attr(target_os = "none", no_std)]
2
3pub mod api;
6
7use core::fmt::Write;
8
9use api::Disconnect;
10use num_traits::ToPrimitive;
11use xous_ipc::Buffer;
12
13#[repr(C, align(4096))]
15struct ConnectRequest {
16 name: [u8; 64],
17 len: u32,
18 _padding: [u8; 4096 - 4 - 64],
19}
20impl Default for ConnectRequest {
21 fn default() -> Self { ConnectRequest { name: [0u8; 64], len: 0, _padding: [0u8; 4096 - 4 - 64] } }
22}
23
24#[doc = include_str!("../README.md")]
25#[derive(Debug)]
26pub struct XousNames {
27 conn: xous::CID,
28}
29impl XousNames {
30 pub fn new() -> Result<Self, xous::Error> {
31 REFCOUNT.fetch_add(1, Ordering::Relaxed);
32 let conn = xous::connect(xous::SID::from_bytes(b"xous-name-server").unwrap())
33 .expect("Couldn't connect to XousNames");
34 Ok(XousNames { conn })
35 }
36
37 pub fn unregister_server(&self, sid: xous::SID) -> Result<(), xous::Error> {
41 let s = sid.to_array();
42 let response = xous::send_message(
43 self.conn,
44 xous::Message::new_blocking_scalar(
45 api::Opcode::Unregister.to_usize().unwrap(),
46 s[0] as usize,
47 s[1] as usize,
48 s[2] as usize,
49 s[3] as usize,
50 ),
51 )
52 .expect("unregistration failed");
53 if let xous::Result::Scalar1(result) = response {
54 if result != 0 { Ok(()) } else { Err(xous::Error::ServerNotFound) }
55 } else {
56 Err(xous::Error::InternalError)
57 }
58 }
59
60 pub fn register_name(&self, name: &str, max_conns: Option<u32>) -> Result<xous::SID, xous::Error> {
65 let mut registration = api::Registration { name: String::new(), conn_limit: max_conns };
66 write!(registration.name, "{}", name).expect("name probably too long");
68
69 let mut buf = Buffer::into_buf(registration).or(Err(xous::Error::InternalError))?;
70
71 buf.lend_mut(self.conn, api::Opcode::Register.to_u32().unwrap())
72 .or(Err(xous::Error::InternalError))?;
73
74 match buf.to_original().unwrap() {
75 api::Return::SID(sid_raw) => {
76 let sid = sid_raw.into();
77 xous::create_server_with_sid(sid).expect("can't auto-register server");
78 Ok(sid)
79 }
80 api::Return::Failure => Err(xous::Error::InternalError),
81 _ => unimplemented!("unimplemented return codes"),
82 }
83 }
84
85 pub fn request_connection_with_token(
90 &self,
91 name: &str,
92 ) -> Result<(xous::CID, Option<[u32; 4]>), xous::Error> {
93 let mut lookup_name = String::new();
94 write!(lookup_name, "{}", name).expect("name probably too long");
95 let mut buf = Buffer::into_buf(lookup_name).or(Err(xous::Error::InternalError))?;
96
97 buf.lend_mut(self.conn, api::Opcode::Lookup.to_u32().unwrap()).or(Err(xous::Error::InternalError))?;
98
99 match buf.to_original().unwrap() {
100 api::Return::CID((cid, token)) => Ok((cid, token)),
101 _ => Err(xous::Error::ServerNotFound),
103 }
104 }
105
106 pub fn disconnect_with_token(&self, name: &str, token: [u32; 4]) -> Result<(), xous::Error> {
109 let disconnect = Disconnect { name: String::from(name), token };
110 let mut buf = Buffer::into_buf(disconnect).or(Err(xous::Error::InternalError))?;
111 buf.lend_mut(self.conn, api::Opcode::Disconnect.to_u32().unwrap())
112 .or(Err(xous::Error::InternalError))?;
113
114 match buf.to_original().unwrap() {
115 api::Return::Success => Ok(()),
116 _ => Err(xous::Error::ServerNotFound),
117 }
118 }
119
120 pub fn request_connection(&self, name: &str) -> Result<xous::CID, xous::Error> {
128 let mut lookup_name = String::new();
129 write!(lookup_name, "{}", name).expect("name probably too long");
130
131 let mut buf = Buffer::into_buf(lookup_name).or(Err(xous::Error::InternalError))?;
132
133 buf.lend_mut(self.conn, api::Opcode::Lookup.to_u32().unwrap()).or(Err(xous::Error::InternalError))?;
134
135 match buf.to_original().unwrap() {
136 api::Return::CID((cid, _)) => Ok(cid),
137 _ => Err(xous::Error::ServerNotFound),
139 }
140 }
141
142 pub fn request_connection_blocking(&self, name: &str) -> Result<xous::CID, xous::Error> {
149 let mut cr: ConnectRequest = Default::default();
150 let name_bytes = name.as_bytes();
151
152 cr.len = cr.name.len().min(name_bytes.len()) as u32;
155
156 for (&src_byte, dest_byte) in name_bytes.iter().zip(&mut cr.name) {
158 *dest_byte = src_byte;
159 }
160 log::debug!("connection requested {}", name);
161 let msg = xous::MemoryMessage {
162 id: api::Opcode::BlockingConnect.to_usize().unwrap(),
163 buf: unsafe {
164 xous::MemoryRange::new(
166 &mut cr as *mut _ as *mut u8 as usize,
167 core::mem::size_of::<ConnectRequest>(),
168 )?
169 },
170 offset: None,
171 valid: xous::MemorySize::new(cr.len as usize),
172 };
173 xous::send_message(self.conn, xous::Message::MutableBorrow(msg))?;
174
175 let response_ptr = &cr as *const ConnectRequest as *const u32;
176 let result = unsafe { response_ptr.read() }; if result == 0 {
179 let cid = unsafe { response_ptr.add(1).read() }.into(); log::debug!("connected to {}:{}", name, cid);
181 Ok(cid)
182 } else {
183 Err(xous::Error::InternalError)
184 }
185 }
186
187 pub fn trusted_init_done(&self) -> Result<bool, xous::Error> {
191 let response = xous::send_message(
192 self.conn,
193 xous::Message::new_blocking_scalar(api::Opcode::TrustedInitDone.to_usize().unwrap(), 0, 0, 0, 0),
194 )
195 .expect("couldn't query trusted_init_done");
196 if let xous::Result::Scalar1(result) = response {
197 if result == 1 { Ok(true) } else { Ok(false) }
198 } else {
199 Err(xous::Error::InternalError)
200 }
201 }
202}
203
204use core::sync::atomic::{AtomicU32, Ordering};
205static REFCOUNT: AtomicU32 = AtomicU32::new(0);
206impl Drop for XousNames {
207 fn drop(&mut self) {
208 if REFCOUNT.fetch_sub(1, Ordering::Relaxed) == 1 {
211 unsafe {
212 xous::disconnect(self.conn).unwrap();
213 }
214 }
215 }
216}