|
@@ -1,4 +1,11 @@
|
|
-// pub mod linux;
|
|
|
|
|
|
+use std::cell::{Cell, RefCell};
|
|
|
|
+use std::collections::VecDeque;
|
|
|
|
+use std::ops::DerefMut;
|
|
|
|
+use std::os::unix::prelude::AsRawFd;
|
|
|
|
+use std::rc::Rc;
|
|
|
|
+
|
|
|
|
+use mio::unix::SourceFd;
|
|
|
|
+use mio::{Events, Interest, Poll, Token};
|
|
|
|
|
|
lazy_static::lazy_static! {
|
|
lazy_static::lazy_static! {
|
|
pub static ref MULTICAST_ADDRESS : std::net::SocketAddrV4 =
|
|
pub static ref MULTICAST_ADDRESS : std::net::SocketAddrV4 =
|
|
@@ -8,13 +15,32 @@ lazy_static::lazy_static! {
|
|
);
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+pub const DEFAULT_PORT: u16 = 3535;
|
|
|
|
+
|
|
|
|
+#[derive(Default)]
|
|
pub struct Packet {
|
|
pub struct Packet {
|
|
pub(crate) addr: Option<std::net::SocketAddr>,
|
|
pub(crate) addr: Option<std::net::SocketAddr>,
|
|
pub(crate) data: Option<Vec<u8>>,
|
|
pub(crate) data: Option<Vec<u8>>,
|
|
- pub(crate) channel: Option<std::rc::Rc<dyn IOChannel>>,
|
|
|
|
|
|
+ pub(crate) io_channel: Option<std::rc::Rc<dyn IOChannel>>,
|
|
pub msg: Option<crate::msg::Message>,
|
|
pub msg: Option<crate::msg::Message>,
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+impl Packet {
|
|
|
|
+ pub fn is_clear(&self) -> bool {
|
|
|
|
+ self.addr.is_none()
|
|
|
|
+ && self.data.is_none()
|
|
|
|
+ && self.io_channel.is_none()
|
|
|
|
+ && self.msg.is_none()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn clear(&mut self) {
|
|
|
|
+ self.addr.take();
|
|
|
|
+ self.data.take();
|
|
|
|
+ self.io_channel.take();
|
|
|
|
+ self.msg.take();
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
pub(crate) trait IOChannel {
|
|
pub(crate) trait IOChannel {
|
|
fn send_packet(&self, packet: &mut Packet);
|
|
fn send_packet(&self, packet: &mut Packet);
|
|
}
|
|
}
|
|
@@ -25,36 +51,220 @@ pub(crate) trait IOFeedback {
|
|
fn major_tick(&self);
|
|
fn major_tick(&self);
|
|
}
|
|
}
|
|
|
|
|
|
-/*pub(crate) trait FleckIO {
|
|
|
|
- fn poll<'a>(&self, f: &dyn IOFeedback);
|
|
|
|
|
|
+pub struct FleckIO {
|
|
|
|
+ poll: Rc<RefCell<mio::Poll>>,
|
|
|
|
+ local: Vec<std::rc::Rc<dyn IOChannel>>,
|
|
|
|
+ global: std::rc::Rc<SocketWrapperChannel>,
|
|
|
|
|
|
- fn local(&self) -> std::rc::Rc<dyn IOChannel>;
|
|
|
|
- fn global(&self) -> std::rc::Rc<dyn IOChannel>;
|
|
|
|
|
|
+ minor: timerfd::TimerFd,
|
|
|
|
+ major: timerfd::TimerFd,
|
|
}
|
|
}
|
|
|
|
|
|
-pub(crate) fn platform() -> std::rc::Rc<dyn FleckIO> {
|
|
|
|
- std::rc::Rc::new(linux::LinuxIO::default())
|
|
|
|
-}*/
|
|
|
|
-
|
|
|
|
-pub struct FleckIO {
|
|
|
|
- local: Vec<std::rc::Rc<dyn IOChannel>>,
|
|
|
|
- global: std::rc::Rc<dyn IOChannel>,
|
|
|
|
|
|
+struct SocketWrapperChannel {
|
|
|
|
+ poll: Rc<RefCell<mio::Poll>>,
|
|
|
|
+ socket: RefCell<mio::net::UdpSocket>,
|
|
|
|
+ queue: RefCell<VecDeque<(Vec<u8>, std::net::SocketAddr)>>,
|
|
|
|
+ write_registered: Cell<bool>,
|
|
}
|
|
}
|
|
|
|
|
|
-impl FleckIO {
|
|
|
|
- pub(crate) fn poll(&self, f: &dyn IOFeedback) {}
|
|
|
|
|
|
+impl SocketWrapperChannel {
|
|
|
|
+ fn new(poll: Rc<RefCell<mio::Poll>>, socket: mio::net::UdpSocket) -> Self {
|
|
|
|
+ Self {
|
|
|
|
+ poll,
|
|
|
|
+ socket: RefCell::new(socket),
|
|
|
|
+ queue: Default::default(),
|
|
|
|
+ write_registered: Cell::new(false),
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn read_packets(&self, feedback: &dyn IOFeedback) {
|
|
|
|
+ let mut buffer = [0u8; 2048];
|
|
|
|
|
|
- pub(crate) fn local(&self) -> &std::rc::Rc<dyn IOChannel> {
|
|
|
|
- todo!()
|
|
|
|
|
|
+ loop {
|
|
|
|
+ match self.socket.borrow().recv_from(&mut buffer) {
|
|
|
|
+ Ok((len, addr)) => {
|
|
|
|
+ feedback.packet(Packet {
|
|
|
|
+ addr: Some(addr),
|
|
|
|
+ data: Some(buffer[..len].into()),
|
|
|
|
+ ..Default::default()
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ Err(_) => break,
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- pub(crate) fn global(&self) -> &std::rc::Rc<dyn IOChannel> {
|
|
|
|
- &self.global
|
|
|
|
|
|
+ fn write_packets(&self) {
|
|
|
|
+ let mut queue = self.queue.borrow_mut();
|
|
|
|
+ while !queue.is_empty() {
|
|
|
|
+ let pkt = queue.front().unwrap();
|
|
|
|
+ match self.socket.borrow().send_to(&pkt.0, pkt.1) {
|
|
|
|
+ Ok(len) => {
|
|
|
|
+ if len != pkt.0.len() {
|
|
|
|
+ log::warn!("Packet of {} bytes truncated to {} bytes when sending", pkt.0.len(), len);
|
|
|
|
+ }
|
|
|
|
+ queue.pop_front();
|
|
|
|
+ },
|
|
|
|
+ Err(e) => {
|
|
|
|
+ log::info!("Error while sending packet: {:?}", e);
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if queue.is_empty() {
|
|
|
|
+ self.poll
|
|
|
|
+ .borrow()
|
|
|
|
+ .registry()
|
|
|
|
+ .reregister(
|
|
|
|
+ self.socket.borrow_mut().deref_mut(),
|
|
|
|
+ FleckIO::GLOBAL,
|
|
|
|
+ Interest::READABLE,
|
|
|
|
+ )
|
|
|
|
+ .expect("couldn't update interest?");
|
|
|
|
+ self.write_registered.set(false);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl IOChannel for SocketWrapperChannel {
|
|
|
|
+ fn send_packet(&self, packet: &mut Packet) {
|
|
|
|
+ assert!(packet.data.is_some());
|
|
|
|
+ assert!(packet.addr.is_some());
|
|
|
|
+
|
|
|
|
+ self.queue
|
|
|
|
+ .borrow_mut()
|
|
|
|
+ .push_back((packet.data.clone().unwrap(), packet.addr.unwrap()));
|
|
|
|
+ if !self.write_registered.get() {
|
|
|
|
+ self.write_registered.set(true);
|
|
|
|
+ self.poll
|
|
|
|
+ .borrow()
|
|
|
|
+ .registry()
|
|
|
|
+ .reregister(
|
|
|
|
+ self.socket.borrow_mut().deref_mut(),
|
|
|
|
+ FleckIO::GLOBAL,
|
|
|
|
+ Interest::READABLE.add(Interest::WRITABLE),
|
|
|
|
+ )
|
|
|
|
+ .expect("couldn't update interest?");
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
impl Default for FleckIO {
|
|
impl Default for FleckIO {
|
|
fn default() -> Self {
|
|
fn default() -> Self {
|
|
- todo!()
|
|
|
|
|
|
+ let poll = Poll::new().expect("couldn't create mio::Poll");
|
|
|
|
+
|
|
|
|
+ // minor tick registration
|
|
|
|
+ let mut minor = timerfd::TimerFd::new().unwrap();
|
|
|
|
+ minor.set_state(
|
|
|
|
+ timerfd::TimerState::Periodic {
|
|
|
|
+ current: std::time::Duration::new(1, 0),
|
|
|
|
+ interval: std::time::Duration::new(1, 0),
|
|
|
|
+ },
|
|
|
|
+ timerfd::SetTimeFlags::Default,
|
|
|
|
+ );
|
|
|
|
+ poll.registry()
|
|
|
|
+ .register(
|
|
|
|
+ &mut SourceFd(&minor.as_raw_fd()),
|
|
|
|
+ Self::MINOR_TICK,
|
|
|
|
+ Interest::READABLE,
|
|
|
|
+ )
|
|
|
|
+ .expect("couldn't register read interest for minor timer?");
|
|
|
|
+
|
|
|
|
+ // major tick registration
|
|
|
|
+ let mut major = timerfd::TimerFd::new().unwrap();
|
|
|
|
+ major.set_state(
|
|
|
|
+ timerfd::TimerState::Periodic {
|
|
|
|
+ current: std::time::Duration::new(1, 0),
|
|
|
|
+ interval: std::time::Duration::new(15, 0),
|
|
|
|
+ },
|
|
|
|
+ timerfd::SetTimeFlags::Default,
|
|
|
|
+ );
|
|
|
|
+ poll.registry()
|
|
|
|
+ .register(
|
|
|
|
+ &mut SourceFd(&major.as_raw_fd()),
|
|
|
|
+ Self::MAJOR_TICK,
|
|
|
|
+ Interest::READABLE,
|
|
|
|
+ )
|
|
|
|
+ .expect("couldn't register read interest for major timer?");
|
|
|
|
+
|
|
|
|
+ // global socket
|
|
|
|
+ let mut global_socket = mio::net::UdpSocket::bind(
|
|
|
|
+ std::net::SocketAddrV4::new(std::net::Ipv4Addr::UNSPECIFIED, DEFAULT_PORT).into(),
|
|
|
|
+ )
|
|
|
|
+ .expect("couldn't listen on UDP port?");
|
|
|
|
+ global_socket
|
|
|
|
+ .join_multicast_v4(&MULTICAST_ADDRESS.ip(), &std::net::Ipv4Addr::UNSPECIFIED)
|
|
|
|
+ .expect("couldn't join multicast group?");
|
|
|
|
+
|
|
|
|
+ poll.registry()
|
|
|
|
+ .register(&mut global_socket, Self::GLOBAL, Interest::READABLE)
|
|
|
|
+ .expect("couldn't register read interest in UDP port?");
|
|
|
|
+
|
|
|
|
+ let poll = Rc::new(RefCell::new(poll));
|
|
|
|
+
|
|
|
|
+ Self {
|
|
|
|
+ global: Rc::new(SocketWrapperChannel::new(poll.clone(), global_socket)),
|
|
|
|
+ local: Default::default(),
|
|
|
|
+ poll,
|
|
|
|
+ major,
|
|
|
|
+ minor
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+impl FleckIO {
|
|
|
|
+ fn handle_event(&self, feedback: &dyn IOFeedback, event: &mio::event::Event) {
|
|
|
|
+ match event.token() {
|
|
|
|
+ Self::GLOBAL => {
|
|
|
|
+ if event.is_readable() {
|
|
|
|
+ self.global.read_packets(feedback);
|
|
|
|
+ }
|
|
|
|
+ if event.is_writable() {
|
|
|
|
+ self.global.write_packets();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ Self::MINOR_TICK => {
|
|
|
|
+ assert!(event.is_readable());
|
|
|
|
+ self.minor.read();
|
|
|
|
+ feedback.minor_tick();
|
|
|
|
+ }
|
|
|
|
+ Self::MAJOR_TICK => {
|
|
|
|
+ assert!(event.is_readable());
|
|
|
|
+ self.major.read();
|
|
|
|
+ feedback.major_tick();
|
|
|
|
+ }
|
|
|
|
+ _ => {
|
|
|
|
+ println!("unknown token!");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub(crate) fn poll(&self, feedback: &dyn IOFeedback) {
|
|
|
|
+ let mut events = Events::with_capacity(128);
|
|
|
|
+ loop {
|
|
|
|
+ let pr = self.poll.borrow_mut().poll(&mut events, None);
|
|
|
|
+ match pr {
|
|
|
|
+ Ok(()) => {
|
|
|
|
+ for evt in &events {
|
|
|
|
+ self.handle_event(feedback, evt);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ Err(_e) => {}
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub(crate) fn local(&self) -> std::rc::Rc<dyn IOChannel> {
|
|
|
|
+ // HACK: for now we just use the global
|
|
|
|
+ self.global.clone()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub(crate) fn global(&self) -> std::rc::Rc<dyn IOChannel> {
|
|
|
|
+ self.global.clone()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const GLOBAL: Token = Token(0);
|
|
|
|
+ const MAJOR_TICK: Token = Token(1);
|
|
|
|
+ const MINOR_TICK: Token = Token(2);
|
|
|
|
+}
|