alnyan/yggdrasil: Add LookupHost and TimerFd
This commit is contained in:
@@ -7175,6 +7175,7 @@ name = "yggdrasil-abi"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ pub mod pipe;
|
||||
pub mod poll;
|
||||
pub mod shared_memory;
|
||||
pub mod terminal;
|
||||
pub mod timer;
|
||||
|
||||
// Public exports
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
|
||||
use crate::io;
|
||||
use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
|
||||
use crate::sys::cvt_io;
|
||||
use crate::sys::fd::FileDesc;
|
||||
use crate::time::Duration;
|
||||
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub struct TimerFd(FileDesc);
|
||||
|
||||
impl TimerFd {
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn new(repeat: bool) -> io::Result<Self> {
|
||||
let raw = cvt_io(unsafe { syscall::create_timer(repeat) })?;
|
||||
let fd = unsafe { FileDesc::from_raw_fd(raw) };
|
||||
Ok(Self(fd))
|
||||
}
|
||||
|
||||
pub fn start(&mut self, timeout: Duration) -> io::Result<()> {
|
||||
let tval = timeout.as_micros();
|
||||
cvt_io(unsafe { syscall::write(self.0.as_raw_fd(), &tval.to_ne_bytes()) })?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl AsRawFd for TimerFd {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
use yggdrasil_rt::net::dns::{
|
||||
self, DnsClass, DnsMessage, DnsRecordData, DnsReplyCode, DnsType, UdpRequester,
|
||||
};
|
||||
|
||||
use crate::io;
|
||||
use crate::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
|
||||
use crate::os::{
|
||||
fd::AsRawFd,
|
||||
yggdrasil::io::{poll::PollChannel, timer::TimerFd},
|
||||
};
|
||||
use crate::time::Duration;
|
||||
|
||||
pub struct LookupHost {
|
||||
addresses: Vec<IpAddr>,
|
||||
port: u16,
|
||||
}
|
||||
|
||||
struct DnsRequester {
|
||||
nameserver: SocketAddr,
|
||||
|
||||
poll: PollChannel,
|
||||
|
||||
timer: TimerFd,
|
||||
socket: UdpSocket,
|
||||
}
|
||||
|
||||
// TODO remove hardcoded nameserver
|
||||
// Maybe use local resolver?
|
||||
const NAMESERVER: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(11, 0, 0, 1)), 53);
|
||||
|
||||
impl DnsRequester {
|
||||
pub fn new(nameserver: SocketAddr) -> io::Result<Self> {
|
||||
let mut poll = PollChannel::new()?;
|
||||
let timer = TimerFd::new(false)?;
|
||||
let socket = UdpSocket::bind("0.0.0.0:0")?;
|
||||
|
||||
poll.add(timer.as_raw_fd())?;
|
||||
poll.add(socket.as_raw_fd())?;
|
||||
|
||||
Ok(Self { nameserver, poll, timer, socket })
|
||||
}
|
||||
}
|
||||
|
||||
impl UdpRequester for DnsRequester {
|
||||
type Error = io::Error;
|
||||
|
||||
fn send_message(&mut self, message: &[u8]) -> io::Result<()> {
|
||||
self.socket.send_to(message, &self.nameserver)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn receive_message<F: Fn(&[u8]) -> Option<DnsMessage>>(
|
||||
&mut self,
|
||||
map: F,
|
||||
) -> io::Result<DnsMessage> {
|
||||
let mut buffer = [0; 2048];
|
||||
|
||||
self.timer.start(Duration::from_millis(500));
|
||||
|
||||
loop {
|
||||
let (poll_fd, result) = self.poll.wait(None)?.unwrap();
|
||||
result?;
|
||||
|
||||
match poll_fd {
|
||||
fd if fd == self.socket.as_raw_fd() => {
|
||||
let (len, _) = self.socket.recv_from(&mut buffer)?;
|
||||
|
||||
if let Some(message) = map(&buffer[..len]) {
|
||||
return Ok(message);
|
||||
}
|
||||
}
|
||||
fd if fd == self.timer.as_raw_fd() => {
|
||||
return Err(io::Error::new(io::ErrorKind::TimedOut, "DNS query timed out"));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LookupHost {
|
||||
pub fn port(&self) -> u16 {
|
||||
self.port
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for LookupHost {
|
||||
type Item = SocketAddr;
|
||||
|
||||
fn next(&mut self) -> Option<SocketAddr> {
|
||||
let ip = self.addresses.pop()?;
|
||||
Some(SocketAddr::new(ip, self.port))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for LookupHost {
|
||||
type Error = io::Error;
|
||||
|
||||
fn try_from(s: &str) -> io::Result<Self> {
|
||||
use crate::str::FromStr;
|
||||
|
||||
let (hostname, port) = s
|
||||
.rsplit_once(':')
|
||||
.ok_or(io::Error::new(io::ErrorKind::InvalidData, "Invalid host:port combination"))?;
|
||||
let port =
|
||||
u16::from_str(port).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
|
||||
Self::try_from((hostname, port))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
|
||||
type Error = io::Error;
|
||||
|
||||
fn try_from((hostname, port): (&'a str, u16)) -> io::Result<Self> {
|
||||
// TODO randomize xid/cookie
|
||||
let mut requester = DnsRequester::new(NAMESERVER)?;
|
||||
let message = dns::perform_query(&mut requester, hostname, DnsType::A, 12341, 0x12313121)?;
|
||||
|
||||
if message.reply_code != DnsReplyCode::NO_ERROR {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "DNS server returned error"));
|
||||
}
|
||||
|
||||
let mut addresses = vec![];
|
||||
|
||||
for answer in message.answers {
|
||||
let Some(name) = answer.name.0.as_ref() else {
|
||||
continue;
|
||||
};
|
||||
let name = name.trim_end_matches('.');
|
||||
if name != hostname {
|
||||
continue;
|
||||
}
|
||||
|
||||
match (answer.ty, answer.class, &answer.rdata) {
|
||||
(DnsType::A, DnsClass::IN, DnsRecordData::A(address)) => {
|
||||
addresses.push(IpAddr::V4(u32::from(*address).into()));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self { addresses, port })
|
||||
}
|
||||
}
|
||||
@@ -1,58 +1,15 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
// use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
|
||||
// use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
|
||||
// use crate::os::yggdrasil::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
||||
// use crate::sys::io::FileDesc;
|
||||
// use crate::sys_common::{AsInner, FromInner, IntoInner};
|
||||
// use crate::time::Duration;
|
||||
//
|
||||
// pub use crate::sys::{cvt, cvt_r};
|
||||
|
||||
// pub use super::yggdrasil_rt::netc;
|
||||
|
||||
mod dns;
|
||||
mod tcp_listener;
|
||||
mod tcp_stream;
|
||||
mod udp;
|
||||
|
||||
pub use dns::LookupHost;
|
||||
pub use tcp_listener::TcpListener;
|
||||
pub use tcp_stream::TcpStream;
|
||||
pub use udp::UdpSocket;
|
||||
|
||||
use crate::net::SocketAddr;
|
||||
|
||||
pub struct LookupHost(!);
|
||||
|
||||
impl LookupHost {
|
||||
pub fn port(&self) -> u16 {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for LookupHost {
|
||||
type Item = SocketAddr;
|
||||
|
||||
fn next(&mut self) -> Option<SocketAddr> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for LookupHost {
|
||||
type Error = crate::io::Error;
|
||||
|
||||
fn try_from(_s: &str) -> crate::io::Result<Self> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
|
||||
type Error = crate::io::Error;
|
||||
|
||||
fn try_from(_s: (&'a str, u16)) -> crate::io::Result<Self> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
// pub type wrlen_t = usize;
|
||||
|
||||
// #[derive(Debug)]
|
||||
|
||||
Reference in New Issue
Block a user