use std::{
fmt,
io::{self, Read, Write},
net::{Ipv4Addr, SocketAddrV4},
};
use rand::random;
use serde::{Deserialize, Serialize};
use crate::{
config::Config,
io::{LimitedReadFrom, ReadFrom, WriteTo},
message::Message,
net::SocketAddr,
net_addr::Services,
packet::Command,
stream::StreamNumbers,
time::Time,
var_type::VarStr,
};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize, Deserialize)]
pub struct ProtocolVersion(u32);
impl ProtocolVersion {
pub fn new(value: u32) -> Self {
Self(value)
}
pub fn as_u32(self) -> u32 {
self.0
}
}
impl fmt::Display for ProtocolVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl From<u32> for ProtocolVersion {
fn from(value: u32) -> Self {
Self(value)
}
}
impl WriteTo for ProtocolVersion {
fn write_to(&self, w: &mut dyn Write) -> io::Result<()> {
self.0.write_to(w)
}
}
impl ReadFrom for ProtocolVersion {
fn read_from(r: &mut dyn Read) -> io::Result<Self>
where
Self: Sized,
{
Ok(Self(u32::read_from(r)?))
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct NodeNonce(u64);
impl NodeNonce {
pub fn new(value: u64) -> Self {
Self(value)
}
pub fn random() -> Self {
Self(random::<u64>())
}
pub fn as_u64(self) -> u64 {
self.0
}
}
impl fmt::Display for NodeNonce {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:016x}", self.0)
}
}
impl From<u64> for NodeNonce {
fn from(value: u64) -> Self {
Self(value)
}
}
impl WriteTo for NodeNonce {
fn write_to(&self, w: &mut dyn Write) -> io::Result<()> {
self.0.write_to(w)
}
}
impl ReadFrom for NodeNonce {
fn read_from(r: &mut dyn Read) -> io::Result<Self>
where
Self: Sized,
{
Ok(Self(u64::read_from(r)?))
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize, Deserialize)]
pub struct UserAgent(VarStr);
impl UserAgent {
pub fn new(bytes: Vec<u8>) -> Self {
Self(VarStr::new(bytes))
}
}
impl fmt::Display for UserAgent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl From<Vec<u8>> for UserAgent {
fn from(bytes: Vec<u8>) -> Self {
Self(bytes.into())
}
}
impl WriteTo for UserAgent {
fn write_to(&self, w: &mut dyn Write) -> io::Result<()> {
self.0.write_to(w)
}
}
impl LimitedReadFrom for UserAgent {
fn limited_read_from(r: &mut dyn Read, max_len: usize) -> io::Result<Self>
where
Self: Sized,
{
Ok(Self(VarStr::limited_read_from(r, max_len)?))
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Version {
version: ProtocolVersion,
services: Services,
timestamp: Time,
remote_services: Services,
addr_recv: SocketAddr,
services2: Services,
addr_from: SocketAddr,
nonce: NodeNonce,
user_agent: UserAgent,
stream_numbers: StreamNumbers,
}
impl Version {
const MAX_USER_AGENT_LENGTH: usize = 5000 - 3;
pub fn builder(config: &Config, nonce: NodeNonce, user_agent: UserAgent) -> VersionBuilder {
VersionBuilder::new(config, nonce, user_agent)
}
pub fn version(&self) -> ProtocolVersion {
self.version
}
pub fn services(&self) -> Services {
self.services
}
pub fn timestamp(&self) -> Time {
self.timestamp
}
pub fn nonce(&self) -> NodeNonce {
self.nonce
}
pub fn user_agent(&self) -> &UserAgent {
&self.user_agent
}
pub fn stream_numbers(&self) -> &StreamNumbers {
&self.stream_numbers
}
}
impl WriteTo for Version {
fn write_to(&self, w: &mut dyn Write) -> io::Result<()> {
self.version.write_to(w)?;
self.services.write_to(w)?;
self.timestamp.write_to(w)?;
self.remote_services.write_to(w)?;
self.addr_recv.write_to(w)?;
self.services2.write_to(w)?;
self.addr_from.write_to(w)?;
self.nonce.write_to(w)?;
self.user_agent.write_to(w)?;
self.stream_numbers.write_to(w)?;
Ok(())
}
}
impl ReadFrom for Version {
fn read_from(r: &mut dyn Read) -> io::Result<Self>
where
Self: Sized,
{
Ok(Self {
version: ProtocolVersion::read_from(r)?,
services: Services::read_from(r)?,
timestamp: Time::read_from(r)?,
remote_services: Services::read_from(r)?,
addr_recv: SocketAddr::read_from(r)?,
services2: Services::read_from(r)?,
addr_from: SocketAddr::read_from(r)?,
nonce: NodeNonce::read_from(r)?,
user_agent: UserAgent::limited_read_from(r, Self::MAX_USER_AGENT_LENGTH)?,
stream_numbers: StreamNumbers::read_from(r)?,
})
}
}
impl Message for Version {
const COMMAND: Command = Command::VERSION;
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct VersionBuilder {
message: Version,
}
lazy_static! {
pub(crate) static ref LOCAL_SOCKET_ADDR: SocketAddr =
SocketAddr::Ipv4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 8444));
}
impl VersionBuilder {
fn new(config: &Config, nonce: NodeNonce, user_agent: UserAgent) -> Self {
let stream_numbers: StreamNumbers = vec![1_u32.into()].into();
let message = Version {
version: config.protocol_version(),
services: Services::NETWORK,
timestamp: Time::now(),
remote_services: Services::NETWORK,
addr_recv: LOCAL_SOCKET_ADDR.clone(),
services2: Services::NETWORK,
addr_from: LOCAL_SOCKET_ADDR.clone(),
nonce,
user_agent,
stream_numbers,
};
Self { message }
}
pub fn services(&mut self, services: Services) -> &mut Self {
self.message.services = services;
self
}
pub fn timestamp(&mut self, timestamp: Time) -> &mut Self {
self.message.timestamp = timestamp;
self
}
pub fn stream_numbers(&mut self, list: StreamNumbers) -> &mut Self {
self.message.stream_numbers = list;
self
}
pub fn build(&self) -> Version {
self.message.clone()
}
}
#[test]
fn test_version_write_to() {
let config = Config::new();
let stream_numbers: StreamNumbers = vec![1_u32.into(), 2_u32.into()].into();
let test = Version::builder(
&config,
0x0123_4567_89ab_cdef.into(),
b"hello".to_vec().into(),
)
.stream_numbers(stream_numbers)
.build();
let mut bytes = Vec::new();
test.write_to(&mut bytes).unwrap();
bytes[12..20].copy_from_slice(&[0xff; 8]);
let expected = [
0, 0, 0, 3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 127, 0, 0, 1, 0x20, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 127, 0, 0, 1, 0x20, 0xfc, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 5, b'h', b'e', b'l', b'l', b'o', 2, 1, 2, ];
assert_eq!(bytes, expected.to_vec());
}
#[test]
fn test_version_read_from() {
use std::io::Cursor;
let mut bytes = Cursor::new(
[
0, 0, 0, 3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 127, 0, 0, 1, 0x20, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 127, 0, 0, 1, 0x20, 0xfc, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 5, b'h', b'e', b'l', b'l', b'o', 2, 1, 2, ]
.to_vec(),
);
let test = Version::read_from(&mut bytes).unwrap();
let stream_numbers: StreamNumbers = vec![1_u32.into(), 2_u32.into()].into();
let config = Config::new();
let mut expected = Version::builder(
&config,
0x0123_4567_89ab_cdef.into(),
b"hello".to_vec().into(),
)
.stream_numbers(stream_numbers)
.build();
expected.timestamp = 0xffff_ffff_ffff_ffff.into();
assert_eq!(test, expected);
}