use crate::serialization::{Packet, PacketDeserializer};
use crate::serialization::header::Header;
use std::error::Error;
use std::collections::HashMap;
use crate::networking::address::Address;
use crate::networking::NetworkSender;
#[cfg(test)]
use std::sync::atomic::AtomicUsize;
pub mod peer;
create_error!(
HeaderUnwrapError,
"The community experienced an error trying to deserialize the header of a packet"
);
create_error!(MidError, "Failed to get the mid");
create_error!(
UnknownCommunityError,
"No community with matching mid found"
);
#[cfg(test)]
static WARN_DEPRECATED_CALLS: AtomicUsize = AtomicUsize::new(0);
pub trait Community {
fn new(endpoint: &NetworkSender) -> Result<Self, Box<dyn Error>>
where
Self: Sized;
fn get_mid(&self) -> Vec<u8>;
#[doc(hidden)]
fn receive(
&self,
header: Header,
deserializer: PacketDeserializer,
address: Address,
) -> Result<(), Box<dyn Error>> {
#[doc(hidden)]
fn warn_deprecated(message: &str, address: Address) -> Result<(), Box<dyn Error>> {
warn!(
"Received deprecated message {} from ({:?})",
message, address
);
#[cfg(test)]
{
WARN_DEPRECATED_CALLS.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
}
Ok(())
}
match header.message_type.ok_or(HeaderUnwrapError)? {
255 => warn_deprecated("reserved-255", address),
254 => warn_deprecated("on-missing-sequence", address),
253 => warn_deprecated("missing-proof", address),
252 => warn_deprecated("signature-request", address),
251 => warn_deprecated("signature-response", address),
248 => warn_deprecated("on-identity", address),
247 => warn_deprecated("on-missing-identity", address),
244 => warn_deprecated("destroy-community", address),
243 => warn_deprecated("authorize", address),
242 => warn_deprecated("revoke", address),
241 => warn_deprecated("subjective-set", address),
240 => warn_deprecated("missing-subjective-set", address),
239 => warn_deprecated("on-missing-message", address),
238 => warn_deprecated("undo-own", address),
237 => warn_deprecated("undo-other", address),
236 => warn_deprecated("dynamic-settings", address),
235 => warn_deprecated("missing-last-message", address),
_ => self.on_receive(header, deserializer, address),
}
}
fn on_receive(
&self,
header: Header,
deserializer: PacketDeserializer,
address: Address,
) -> Result<(), Box<dyn Error>>;
}
pub struct CommunityRegistry {
#[cfg(test)]
pub communities: HashMap<Vec<u8>, Box<dyn Community>>,
#[cfg(not(test))]
communities: HashMap<Vec<u8>, Box<dyn Community>>,
}
impl CommunityRegistry {
pub fn add_community(&mut self, item: Box<dyn Community>) -> Result<(), Box<dyn Error>> {
match self.communities.insert(item.get_mid(), item) {
_ => Ok(()),
}
}
pub fn forward_message(&self, packet: Packet, address: Address) -> Result<(), Box<dyn Error>> {
let deserializer = packet.start_deserialize();
let header = deserializer.peek_header()?;
let mid = header.mid_hash.as_ref().ok_or(MidError)?;
let community = self.communities.get(mid).ok_or(UnknownCommunityError)?;
community.receive(header, deserializer, address)
}
}
impl Default for CommunityRegistry {
fn default() -> Self {
Self {
communities: HashMap::new(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::networking::address::Address;
use std::net::{SocketAddr, IpAddr};
use std::error::Error;
use crate::networking::NetworkSender;
use crate::community::peer::Peer;
use crate::community::{Community, CommunityRegistry};
use crate::serialization::header::Header;
use crate::serialization::{PacketDeserializer, Packet};
use std::net::Ipv4Addr;
use crate::IPv8;
use crate::configuration::Config;
use crate::serialization::header::HeaderVersion::PyIPV8Header;
use std::sync::atomic::Ordering;
use crate::networking::test_helper::localhost;
use crate::crypto::signature::KeyPair;
pub struct TestCommunity {
peer: Peer,
}
impl Community for TestCommunity {
fn new(_endpoint: &NetworkSender) -> Result<Self, Box<dyn Error>> {
let pk = KeyPair::from_seed_unchecked(&[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31,
])
.unwrap();
Ok(TestCommunity {
peer: Peer::new(
pk.public_key().unwrap(),
Address(SocketAddr::new(
IpAddr::V4(Ipv4Addr::new(42, 42, 42, 42)),
8000,
)),
true,
),
})
}
fn get_mid(&self) -> Vec<u8> {
self.peer.get_sha1()
}
fn on_receive(
&self,
header: Header,
_deserializer: PacketDeserializer,
_address: Address,
) -> Result<(), Box<dyn Error>> {
assert_eq!(header.mid_hash.unwrap(), self.get_mid());
assert_eq!(header.version, PyIPV8Header);
assert_eq!(header.message_type, Some(42));
Ok(())
}
}
#[test]
fn test_deprecated() {
let mut config = Config::default();
config.sending_address = Address(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0));
config.receiving_address =
Address(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0));
let ipv8 = IPv8::new(config).unwrap();
let community = TestCommunity::new(&ipv8.network_sender).unwrap();
for i in &[
255, 254, 253, 252, 251, 248, 247, 244, 243, 242, 241, 240, 239, 238, 237, 236, 235,
] {
let address = Address(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0));
let packet = Packet::new(Header {
size: 23,
version: PyIPV8Header,
mid_hash: Some(community.get_mid()),
message_type: Some(*i),
})
.unwrap();
let deser = packet.start_deserialize();
let header = deser.peek_header().unwrap();
community.receive(header, deser, address).unwrap();
}
assert_eq!(17, WARN_DEPRECATED_CALLS.load(Ordering::SeqCst))
}
#[test]
fn test_add_community() {
let config = Config::default();
let ipv8 = IPv8::new(config).unwrap();
let community = Box::new(TestCommunity::new(&ipv8.network_sender).unwrap());
let the_same = Box::new(TestCommunity::new(&ipv8.network_sender).unwrap());
let mid = &*community.get_mid();
let mut registry: CommunityRegistry = CommunityRegistry::default();
registry.add_community(community).unwrap();
let get = registry.communities.get(mid).unwrap();
assert_eq!(the_same.get_mid(), get.get_mid());
}
#[test]
fn test_networking() {
let mut config = Config::default();
config.receiving_address = localhost();
config.sending_address = localhost();
config.buffersize = 2048;
let mut ipv8 = IPv8::new(config).unwrap();
let community = TestCommunity::new(&ipv8.network_sender).unwrap();
let mid = community.get_mid();
ipv8.communities.add_community(Box::new(community)).unwrap();
let packet = Packet::new(Header {
size: 23,
version: PyIPV8Header,
mid_hash: Some(mid),
message_type: Some(42),
})
.unwrap();
ipv8.communities
.forward_message(
packet,
Address(SocketAddr::new(
IpAddr::V4(Ipv4Addr::new(42, 42, 42, 42)),
42,
)),
)
.unwrap();
}
}