Skip to content

Commit dcaf4b5

Browse files
committed
xous: net: initial commit of network support
This is an initial commit of network support for Xous. On hardware, is backed by smoltcp running via a Xous server in a separate process space. This patch adds TCP and UDP client and server support as well as DNS resolution support using the dns Xous server. Signed-off-by: Sean Cross <[email protected]>
1 parent d8ab51d commit dcaf4b5

File tree

9 files changed

+1496
-1
lines changed

9 files changed

+1496
-1
lines changed

library/std/src/os/xous/services.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
use crate::os::xous::ffi::Connection;
22
use core::sync::atomic::{AtomicU32, Ordering};
33

4+
mod dns;
5+
pub(crate) use dns::*;
6+
47
mod log;
58
pub(crate) use log::*;
69

10+
mod net;
11+
pub(crate) use net::*;
12+
713
mod systime;
814
pub(crate) use systime::*;
915

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use crate::os::xous::ffi::Connection;
2+
use crate::os::xous::services::connect;
3+
use core::sync::atomic::{AtomicU32, Ordering};
4+
5+
#[repr(usize)]
6+
pub(crate) enum DnsLendMut {
7+
RawLookup, /* 6 */
8+
}
9+
10+
impl Into<usize> for DnsLendMut {
11+
fn into(self) -> usize {
12+
match self {
13+
DnsLendMut::RawLookup => 6,
14+
}
15+
}
16+
}
17+
18+
/// Return a `Connection` to the DNS lookup server. This server is used for
19+
/// querying domain name values.
20+
pub(crate) fn dns_server() -> Connection {
21+
static DNS_CONNECTION: AtomicU32 = AtomicU32::new(0);
22+
let cid = DNS_CONNECTION.load(Ordering::Relaxed);
23+
if cid != 0 {
24+
return cid.into();
25+
}
26+
27+
let cid = connect("_DNS Resolver Middleware_").unwrap();
28+
DNS_CONNECTION.store(cid.into(), Ordering::Relaxed);
29+
cid
30+
}
+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
use crate::os::xous::ffi::Connection;
2+
use crate::os::xous::services::connect;
3+
use core::sync::atomic::{AtomicU32, Ordering};
4+
5+
pub(crate) enum NetBlockingScalar {
6+
StdGetTtlUdp(u16 /* fd */), /* 36 */
7+
StdSetTtlUdp(u16 /* fd */, u32 /* ttl */), /* 37 */
8+
StdGetTtlTcp(u16 /* fd */), /* 36 */
9+
StdSetTtlTcp(u16 /* fd */, u32 /* ttl */), /* 37 */
10+
StdGetNodelay(u16 /* fd */), /* 38 */
11+
StdSetNodelay(u16 /* fd */, bool), /* 39 */
12+
StdTcpClose(u16 /* fd */), /* 34 */
13+
StdUdpClose(u16 /* fd */), /* 41 */
14+
StdTcpStreamShutdown(u16 /* fd */, crate::net::Shutdown /* how */), /* 46 */
15+
}
16+
17+
pub(crate) enum NetLendMut {
18+
StdTcpConnect, /* 30 */
19+
StdTcpTx(u16 /* fd */), /* 31 */
20+
StdTcpPeek(u16 /* fd */, bool /* nonblocking */), /* 32 */
21+
StdTcpRx(u16 /* fd */, bool /* nonblocking */), /* 33 */
22+
StdGetAddress(u16 /* fd */), /* 35 */
23+
StdUdpBind, /* 40 */
24+
StdUdpRx(u16 /* fd */), /* 42 */
25+
StdUdpTx(u16 /* fd */), /* 43 */
26+
StdTcpListen, /* 44 */
27+
StdTcpAccept(u16 /* fd */), /* 45 */
28+
}
29+
30+
impl Into<usize> for NetLendMut {
31+
fn into(self) -> usize {
32+
match self {
33+
NetLendMut::StdTcpConnect => 30,
34+
NetLendMut::StdTcpTx(fd) => 31 | ((fd as usize) << 16),
35+
NetLendMut::StdTcpPeek(fd, blocking) => {
36+
32 | ((fd as usize) << 16) | if blocking { 0x8000 } else { 0 }
37+
}
38+
NetLendMut::StdTcpRx(fd, blocking) => {
39+
33 | ((fd as usize) << 16) | if blocking { 0x8000 } else { 0 }
40+
}
41+
NetLendMut::StdGetAddress(fd) => 35 | ((fd as usize) << 16),
42+
NetLendMut::StdUdpBind => 40,
43+
NetLendMut::StdUdpRx(fd) => 42 | ((fd as usize) << 16),
44+
NetLendMut::StdUdpTx(fd) => 43 | ((fd as usize) << 16),
45+
NetLendMut::StdTcpListen => 44,
46+
NetLendMut::StdTcpAccept(fd) => 45 | ((fd as usize) << 16),
47+
}
48+
}
49+
}
50+
51+
impl<'a> Into<[usize; 5]> for NetBlockingScalar {
52+
fn into(self) -> [usize; 5] {
53+
match self {
54+
NetBlockingScalar::StdGetTtlTcp(fd) => [36 | ((fd as usize) << 16), 0, 0, 0, 0],
55+
NetBlockingScalar::StdGetTtlUdp(fd) => [36 | ((fd as usize) << 16), 0, 0, 0, 1],
56+
NetBlockingScalar::StdSetTtlTcp(fd, ttl) => {
57+
[37 | ((fd as usize) << 16), ttl as _, 0, 0, 0]
58+
}
59+
NetBlockingScalar::StdSetTtlUdp(fd, ttl) => {
60+
[37 | ((fd as usize) << 16), ttl as _, 0, 0, 1]
61+
}
62+
NetBlockingScalar::StdGetNodelay(fd) => [38 | ((fd as usize) << 16), 0, 0, 0, 0],
63+
NetBlockingScalar::StdSetNodelay(fd, enabled) => {
64+
[39 | ((fd as usize) << 16), if enabled { 1 } else { 0 }, 0, 0, 1]
65+
}
66+
NetBlockingScalar::StdTcpClose(fd) => [34 | ((fd as usize) << 16), 0, 0, 0, 0],
67+
NetBlockingScalar::StdUdpClose(fd) => [41 | ((fd as usize) << 16), 0, 0, 0, 0],
68+
NetBlockingScalar::StdTcpStreamShutdown(fd, how) => [
69+
46 | ((fd as usize) << 16),
70+
match how {
71+
crate::net::Shutdown::Read => 1,
72+
crate::net::Shutdown::Write => 2,
73+
crate::net::Shutdown::Both => 3,
74+
},
75+
0,
76+
0,
77+
0,
78+
],
79+
}
80+
}
81+
}
82+
83+
/// Return a `Connection` to the Network server. This server provides all
84+
/// OS-level networking functions.
85+
pub(crate) fn net_server() -> Connection {
86+
static NET_CONNECTION: AtomicU32 = AtomicU32::new(0);
87+
let cid = NET_CONNECTION.load(Ordering::Relaxed);
88+
if cid != 0 {
89+
return cid.into();
90+
}
91+
92+
let cid = connect("_Middleware Network Server_").unwrap();
93+
NET_CONNECTION.store(cid.into(), Ordering::Relaxed);
94+
cid
95+
}

library/std/src/sys/xous/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ pub mod fs;
1212
#[path = "../unsupported/io.rs"]
1313
pub mod io;
1414
pub mod locks;
15-
#[path = "../unsupported/net.rs"]
1615
pub mod net;
1716
pub mod os;
1817
#[path = "../unix/os_str.rs"]

library/std/src/sys/xous/net/dns.rs

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
use crate::io;
2+
use crate::net::{Ipv4Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
3+
use crate::os::xous::ffi::lend_mut;
4+
use crate::os::xous::services::{dns_server, DnsLendMut};
5+
use core::convert::{TryFrom, TryInto};
6+
7+
pub struct DnsError {
8+
pub code: u8,
9+
}
10+
11+
#[repr(C, align(4096))]
12+
struct LookupHostQuery([u8; 4096]);
13+
14+
pub struct LookupHost {
15+
data: LookupHostQuery,
16+
port: u16,
17+
offset: usize,
18+
count: usize,
19+
}
20+
21+
impl LookupHost {
22+
pub fn port(&self) -> u16 {
23+
self.port
24+
}
25+
}
26+
27+
impl Iterator for LookupHost {
28+
type Item = SocketAddr;
29+
fn next(&mut self) -> Option<SocketAddr> {
30+
if self.offset >= self.data.0.len() {
31+
return None;
32+
}
33+
match self.data.0.get(self.offset) {
34+
Some(&4) => {
35+
self.offset += 1;
36+
if self.offset + 4 > self.data.0.len() {
37+
return None;
38+
}
39+
let result = Some(SocketAddr::V4(SocketAddrV4::new(
40+
Ipv4Addr::new(
41+
self.data.0[self.offset],
42+
self.data.0[self.offset + 1],
43+
self.data.0[self.offset + 2],
44+
self.data.0[self.offset + 3],
45+
),
46+
self.port,
47+
)));
48+
self.offset += 4;
49+
result
50+
}
51+
Some(&6) => {
52+
self.offset += 1;
53+
if self.offset + 16 > self.data.0.len() {
54+
return None;
55+
}
56+
let mut new_addr = [0u8; 16];
57+
for (src, octet) in self.data.0[(self.offset + 1)..(self.offset + 16 + 1)]
58+
.iter()
59+
.zip(new_addr.iter_mut())
60+
{
61+
*octet = *src;
62+
}
63+
let result =
64+
Some(SocketAddr::V6(SocketAddrV6::new(new_addr.into(), self.port, 0, 0)));
65+
self.offset += 16;
66+
result
67+
}
68+
_ => None,
69+
}
70+
}
71+
}
72+
73+
pub fn lookup(query: &str, port: u16) -> Result<LookupHost, DnsError> {
74+
let mut result = LookupHost { data: LookupHostQuery([0u8; 4096]), offset: 0, count: 0, port };
75+
76+
// Copy the query into the message that gets sent to the DNS server
77+
for (query_byte, result_byte) in query.as_bytes().iter().zip(result.data.0.iter_mut()) {
78+
*result_byte = *query_byte;
79+
}
80+
81+
lend_mut(
82+
dns_server(),
83+
DnsLendMut::RawLookup.into(),
84+
&mut result.data.0,
85+
0,
86+
query.as_bytes().len(),
87+
)
88+
.unwrap();
89+
if result.data.0[0] != 0 {
90+
return Err(DnsError { code: result.data.0[1] });
91+
}
92+
assert_eq!(result.offset, 0);
93+
result.count = result.data.0[1] as usize;
94+
95+
// Advance the offset to the first record
96+
result.offset = 2;
97+
Ok(result)
98+
}
99+
100+
impl TryFrom<&str> for LookupHost {
101+
type Error = io::Error;
102+
103+
fn try_from(s: &str) -> io::Result<LookupHost> {
104+
macro_rules! try_opt {
105+
($e:expr, $msg:expr) => {
106+
match $e {
107+
Some(r) => r,
108+
None => return Err(io::const_io_error!(io::ErrorKind::InvalidInput, &$msg)),
109+
// None => return Err(io::Error::new(io::ErrorKind::AddrInUse, "error")),
110+
}
111+
};
112+
}
113+
114+
// split the string by ':' and convert the second part to u16
115+
let (host, port_str) = try_opt!(s.rsplit_once(':'), "invalid socket address");
116+
let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value");
117+
(host, port).try_into()
118+
}
119+
}
120+
121+
impl TryFrom<(&str, u16)> for LookupHost {
122+
type Error = io::Error;
123+
124+
fn try_from(v: (&str, u16)) -> io::Result<LookupHost> {
125+
lookup(v.0, v.1)
126+
.map_err(|_e| io::const_io_error!(io::ErrorKind::InvalidInput, &"DNS failure"))
127+
}
128+
}

library/std/src/sys/xous/net/mod.rs

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
mod dns;
2+
3+
mod tcpstream;
4+
pub use tcpstream::*;
5+
6+
mod tcplistener;
7+
pub use tcplistener::*;
8+
9+
mod udp;
10+
pub use udp::*;
11+
12+
// this structure needs to be synchronized with what's in net/src/api.rs
13+
#[repr(C)]
14+
#[derive(Debug)]
15+
enum NetError {
16+
// Ok = 0,
17+
Unaddressable = 1,
18+
SocketInUse = 2,
19+
// AccessDenied = 3,
20+
Invalid = 4,
21+
// Finished = 5,
22+
LibraryError = 6,
23+
// AlreadyUsed = 7,
24+
TimedOut = 8,
25+
WouldBlock = 9,
26+
}
27+
28+
#[repr(C, align(4096))]
29+
struct ConnectRequest {
30+
raw: [u8; 4096],
31+
}
32+
33+
#[repr(C, align(4096))]
34+
struct SendData {
35+
raw: [u8; 4096],
36+
}
37+
38+
#[repr(C, align(4096))]
39+
pub struct ReceiveData {
40+
raw: [u8; 4096],
41+
}
42+
43+
#[repr(C, align(4096))]
44+
pub struct GetAddress {
45+
raw: [u8; 4096],
46+
}
47+
48+
pub use dns::LookupHost;
49+
50+
#[allow(nonstandard_style)]
51+
pub mod netc {
52+
pub const AF_INET: u8 = 0;
53+
pub const AF_INET6: u8 = 1;
54+
pub type sa_family_t = u8;
55+
56+
#[derive(Copy, Clone)]
57+
pub struct in_addr {
58+
pub s_addr: u32,
59+
}
60+
61+
#[derive(Copy, Clone)]
62+
pub struct sockaddr_in {
63+
pub sin_family: sa_family_t,
64+
pub sin_port: u16,
65+
pub sin_addr: in_addr,
66+
}
67+
68+
#[derive(Copy, Clone)]
69+
pub struct in6_addr {
70+
pub s6_addr: [u8; 16],
71+
}
72+
73+
#[derive(Copy, Clone)]
74+
pub struct sockaddr_in6 {
75+
pub sin6_family: sa_family_t,
76+
pub sin6_port: u16,
77+
pub sin6_addr: in6_addr,
78+
pub sin6_flowinfo: u32,
79+
pub sin6_scope_id: u32,
80+
}
81+
82+
#[derive(Copy, Clone)]
83+
pub struct sockaddr {}
84+
}

0 commit comments

Comments
 (0)