|
@@ -0,0 +1,271 @@
|
|
|
+use std::{rc::Rc, cell::{RefCell, Cell}, os::unix::prelude::{RawFd, AsRawFd}, collections::{HashMap, VecDeque}};
|
|
|
+
|
|
|
+use crate::prelude::*;
|
|
|
+
|
|
|
+pub struct InterestRegistration {
|
|
|
+ poll: Rc<RefCell<mio::Poll>>,
|
|
|
+ token: mio::Token,
|
|
|
+ fd: RawFd,
|
|
|
+ interest: Cell<mio::Interest>,
|
|
|
+}
|
|
|
+
|
|
|
+impl InterestRegistration {
|
|
|
+ pub fn update_interest(&self, to: mio::Interest) {
|
|
|
+ if self.interest.get() != to {
|
|
|
+ self.poll.borrow().registry().reregister(
|
|
|
+ &mut mio::unix::SourceFd(&self.fd),
|
|
|
+ self.token,
|
|
|
+ to
|
|
|
+ ).expect("couldn't update FD interest");
|
|
|
+ self.interest.set(to);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub trait FdHandler {
|
|
|
+ fn ready_read(&self, rc: &Rc<dyn FdHandler>, api: &crate::Fleck);
|
|
|
+ fn ready_write(&self, rc: &Rc<dyn FdHandler>, api: &crate::Fleck);
|
|
|
+ fn dispatch(&self, api: &crate::Fleck, msg: super::msg::Message);
|
|
|
+}
|
|
|
+
|
|
|
+/*pub(crate) struct FdHandler {
|
|
|
+ pub(crate) ready_read: Rc<dyn Fn(&crate::Fleck)>,
|
|
|
+ pub(crate) ready_write: Rc<dyn Fn(&crate::Fleck)>,
|
|
|
+ pub(crate) dispatch: Rc<dyn Fn(&crate::Fleck, super::msg::Message)>,
|
|
|
+ owned: Rc<dyn std::any::Any>,
|
|
|
+}*/
|
|
|
+
|
|
|
+pub struct IOService {
|
|
|
+ poll: Rc<RefCell<mio::Poll>>,
|
|
|
+ next_token: Cell<mio::Token>,
|
|
|
+ handlers: RefCell<HashMap<mio::Token, Rc<dyn FdHandler>>>,
|
|
|
+}
|
|
|
+
|
|
|
+impl Default for IOService {
|
|
|
+ fn default() -> Self {
|
|
|
+ Self {
|
|
|
+ poll: Rc::new(RefCell::new(mio::Poll::new().expect("couldn't create poll?"))),
|
|
|
+ next_token: Cell::new(mio::Token(1)),
|
|
|
+ handlers: Default::default(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl Service for Rc<IOService> { }
|
|
|
+
|
|
|
+impl IOService {
|
|
|
+ pub fn register_handler(&self, reg: &InterestRegistration, handler: Rc<dyn FdHandler>) {
|
|
|
+ self.handlers.borrow_mut().insert(reg.token, handler);
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn register_interest(&self, fd: RawFd) -> InterestRegistration {
|
|
|
+ let token = self.next_token.get();
|
|
|
+ self.next_token.set(mio::Token(token.0 + 1));
|
|
|
+
|
|
|
+ self.poll.borrow().registry().register(
|
|
|
+ &mut mio::unix::SourceFd(&fd),
|
|
|
+ token,
|
|
|
+ mio::Interest::READABLE,
|
|
|
+ ).expect("couldn't register initial readable interest?");
|
|
|
+
|
|
|
+ InterestRegistration {
|
|
|
+ poll: self.poll.clone(),
|
|
|
+ token,
|
|
|
+ fd,
|
|
|
+ interest: Cell::new(mio::Interest::READABLE),
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pub(crate) fn run(&self, api: &crate::Fleck) {
|
|
|
+ let mut events = mio::Events::with_capacity(128);
|
|
|
+ loop {
|
|
|
+ let pr = self.poll.borrow_mut().poll(&mut events, None);
|
|
|
+ if pr.is_err() {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ let handlers = self.handlers.borrow();
|
|
|
+ for evt in &events {
|
|
|
+ let h = handlers.get(&evt.token()).unwrap();
|
|
|
+ if evt.is_readable() {
|
|
|
+ h.ready_read(h, api);
|
|
|
+ }
|
|
|
+ if evt.is_writable() {
|
|
|
+ h.ready_write(h, api);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ api.services.event_root().fire_all(api);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[derive(Default)]
|
|
|
+pub struct UdpSocketBuilder {
|
|
|
+ bind: Option<std::net::SocketAddr>,
|
|
|
+ multicast: Vec<(std::net::IpAddr, std::net::IpAddr)>,
|
|
|
+}
|
|
|
+
|
|
|
+impl UdpSocketBuilder {
|
|
|
+ pub fn bind_to(mut self, addr: std::net::SocketAddr) -> Self {
|
|
|
+ self.bind = Some(addr);
|
|
|
+ self
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn join_multicast(mut self, group: std::net::IpAddr, iface: std::net::IpAddr) -> Self {
|
|
|
+ self.multicast.push((group, iface));
|
|
|
+ self
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn build(self, io: &IOService) {
|
|
|
+ let socket = mio::net::UdpSocket::bind(self.bind.expect("no bind address given to UDP socket!")).expect("couldn't bind UDP socket");
|
|
|
+ let interest = io.register_interest(socket.as_raw_fd());
|
|
|
+
|
|
|
+ for mcast in self.multicast {
|
|
|
+ use std::net::IpAddr;
|
|
|
+ match (mcast.0, mcast.1) {
|
|
|
+ (IpAddr::V4(group), IpAddr::V4(iface)) => {
|
|
|
+ socket.join_multicast_v4(&group, &iface).expect("couldn't join multicast group");
|
|
|
+ },
|
|
|
+ (IpAddr::V6(_group), IpAddr::V6(_iface)) => {
|
|
|
+ todo!()
|
|
|
+ },
|
|
|
+ _ => panic!("Multicast specification mixes ipv4 and ipv6 addresses!"),
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let sock = Rc::new(UdpSocket {
|
|
|
+ interest,
|
|
|
+ socket,
|
|
|
+ queue: Default::default(),
|
|
|
+ peers: Default::default(),
|
|
|
+ });
|
|
|
+
|
|
|
+ io.register_handler(&sock.interest, sock.clone());
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+struct UdpSocket {
|
|
|
+ interest: InterestRegistration,
|
|
|
+ socket: mio::net::UdpSocket,
|
|
|
+ queue: RefCell<VecDeque<(std::net::SocketAddr, Vec<u8>)>>,
|
|
|
+ peers: RefCell<HashMap<std::net::SocketAddr, super::peer::Peer>>,
|
|
|
+}
|
|
|
+
|
|
|
+impl UdpSocket {
|
|
|
+ fn peer_for(&self, rc: &Rc<dyn FdHandler>, addr: &std::net::SocketAddr) -> super::peer::Peer {
|
|
|
+ if let Some(peer) = self.peers.borrow().get(addr) {
|
|
|
+ peer.clone()
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ let peer = super::peer::Peer {
|
|
|
+ data: Rc::new(super::peer::PeerData {
|
|
|
+ address_info: super::peer::PeerAddress::Udp(*addr),
|
|
|
+ io: rc.clone(),
|
|
|
+ })
|
|
|
+ };
|
|
|
+ self.peers.borrow_mut().insert(*addr, peer.clone());
|
|
|
+ peer
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl FdHandler for UdpSocket {
|
|
|
+ fn ready_read(&self, rc: &Rc<dyn FdHandler>, api: &crate::Fleck) {
|
|
|
+ let mut buf = [0u8; 2048];
|
|
|
+ while let Ok((bytes, addr)) = self.socket.recv_from(&mut buf) {
|
|
|
+ if let Ok(mut msg) = bincode::deserialize::<super::msg::Message>(&buf[..bytes]) {
|
|
|
+ msg.peer = Some(self.peer_for(rc, &addr));
|
|
|
+ api.queue::<super::ReceivePacketChannel>(msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ fn ready_write(&self, _rc: &Rc<dyn FdHandler>, _api: &crate::Fleck) {
|
|
|
+ let queue = self.queue.borrow_mut();
|
|
|
+ while !queue.is_empty() {
|
|
|
+ let packet = queue.front().unwrap();
|
|
|
+
|
|
|
+ if let Ok(len) = self.socket.send_to(&packet.1, packet.0) {
|
|
|
+ if len != packet.1.len() {
|
|
|
+ log::error!("Sent packet truncated to {} of {} bytes", len, packet.1.len());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ self.interest.update_interest(mio::Interest::READABLE);
|
|
|
+ }
|
|
|
+
|
|
|
+ fn dispatch(&self, _api: &crate::Fleck, msg: fleck_core::msg::Message) {
|
|
|
+ let peer = msg.peer.clone().unwrap(); // if we got this far, the peer points to us
|
|
|
+
|
|
|
+ if let super::peer::PeerAddress::Udp(addr) = peer.data.address_info {
|
|
|
+ self.queue.borrow_mut().push_back(
|
|
|
+ (addr, bincode::serialize(&msg).expect("couldn't serialize message?")));
|
|
|
+ self.interest.update_interest(mio::Interest::READABLE.add(mio::Interest::WRITABLE));
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ log::error!("packet dispatched to UdpSocket without UDP address!");
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[derive(Default)]
|
|
|
+pub struct TimerFdBuilder {
|
|
|
+ interval: Option<std::time::Duration>,
|
|
|
+ trigger: Option<Box<dyn Fn(&crate::Fleck)>>,
|
|
|
+}
|
|
|
+
|
|
|
+impl TimerFdBuilder {
|
|
|
+ pub fn interval(mut self, interval: std::time::Duration) -> Self {
|
|
|
+ self.interval = Some(interval);
|
|
|
+ self
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn trigger<F: 'static + Fn(&crate::Fleck)>(mut self, f: F) -> Self {
|
|
|
+ self.trigger = Some(Box::new(f));
|
|
|
+ self
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn build(self, io: &IOService) {
|
|
|
+ let mut timer = timerfd::TimerFd::new().expect("couldn't create new timerfd?");
|
|
|
+
|
|
|
+ timer.set_state(timerfd::TimerState::Periodic {
|
|
|
+ current: std::time::Duration::from_millis(1),
|
|
|
+ interval: self.interval.expect("building timerfd with no interval set?"),
|
|
|
+ }, timerfd::SetTimeFlags::Default);
|
|
|
+
|
|
|
+ let interest = io.register_interest(timer.as_raw_fd());
|
|
|
+
|
|
|
+ let sock = Rc::new(TimerFd {
|
|
|
+ interest,
|
|
|
+ timer,
|
|
|
+ trigger: self.trigger.expect("building timerfd with no trigger?"),
|
|
|
+ });
|
|
|
+
|
|
|
+ io.register_handler(&sock.interest, sock.clone());
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+struct TimerFd {
|
|
|
+ interest: InterestRegistration,
|
|
|
+ timer: timerfd::TimerFd,
|
|
|
+ trigger: Box<dyn Fn(&crate::Fleck)>,
|
|
|
+}
|
|
|
+
|
|
|
+impl FdHandler for TimerFd {
|
|
|
+ fn ready_read(&self, _rc: &Rc<dyn FdHandler>, api: &crate::Fleck) {
|
|
|
+ self.timer.read();
|
|
|
+ (self.trigger)(api);
|
|
|
+ }
|
|
|
+
|
|
|
+ fn ready_write(&self, _rc: &Rc<dyn FdHandler>, _api: &crate::Fleck) {
|
|
|
+ unreachable!()
|
|
|
+ }
|
|
|
+
|
|
|
+ fn dispatch(&self, _api: &crate::Fleck, _msg: fleck_core::msg::Message) {
|
|
|
+ unreachable!()
|
|
|
+ }
|
|
|
+}
|