-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b45941e
commit 980667b
Showing
7 changed files
with
335 additions
and
62 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
name: Rust | ||
|
||
on: | ||
push: | ||
branches: [ "main" ] | ||
pull_request: | ||
branches: [ "main" ] | ||
|
||
env: | ||
CARGO_TERM_COLOR: always | ||
|
||
jobs: | ||
build: | ||
|
||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v3 | ||
- name: Build | ||
run: cargo build --verbose | ||
- name: Run tests | ||
run: cargo test --verbose | ||
- name: Check format code | ||
run: cargo fmt -- --check | ||
- name: Clippy | ||
run: cargo clippy -- -D warnings |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
use thiserror::Error; | ||
|
||
pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>; | ||
|
||
pub mod models_errors { | ||
use super::*; | ||
|
||
#[derive(Debug, Clone, Error)] | ||
#[error("The amount of bytes should be divisable by 6")] | ||
pub struct WrongSizeIPv4; | ||
|
||
#[derive(Debug, Clone, Error)] | ||
#[error("The amount of bytes should be divisable by 18")] | ||
pub struct WrongSizeIPv6; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,8 @@ | ||
mod errors; | ||
mod models; | ||
mod node; | ||
#[macro_use] | ||
mod tools; | ||
|
||
fn main() { | ||
println!("Hello, world!"); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,88 +1,234 @@ | ||
use crate::errors::*; | ||
use serde::{Deserialize, Serialize}; | ||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; | ||
|
||
#[repr(u8)] | ||
#[derive(Clone, Copy, PartialEq, Debug, Deserialize, Serialize)] | ||
pub enum ErrorCode{ | ||
ParseError = 1 | ||
} | ||
pub mod packet_models { | ||
use super::*; | ||
|
||
#[derive(Debug, PartialEq, Deserialize, Serialize)] | ||
#[serde(tag = "type")] | ||
pub enum Packet{ | ||
#[allow(non_camel_case_types)] | ||
request(Request), | ||
|
||
#[allow(non_camel_case_types)] | ||
response(Response), | ||
|
||
#[allow(non_camel_case_types)] | ||
error(ErrorR) | ||
} | ||
|
||
#[derive(Debug, PartialEq, Deserialize, Serialize)] | ||
#[serde(tag = "q")] | ||
pub enum Request{ | ||
#[allow(non_camel_case_types)] | ||
get_nodes, | ||
|
||
#[allow(non_camel_case_types)] | ||
get_amount, | ||
|
||
#[allow(non_camel_case_types)] | ||
get_transaction | ||
} | ||
#[repr(u8)] | ||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Deserialize, Serialize)] | ||
pub enum ErrorCode { | ||
ParseError = 1, | ||
} | ||
|
||
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] | ||
#[serde(tag = "type")] | ||
pub enum Packet { | ||
#[allow(non_camel_case_types)] | ||
request(Request), | ||
|
||
#[allow(non_camel_case_types)] | ||
response(Response), | ||
|
||
#[allow(non_camel_case_types)] | ||
error(ErrorR), | ||
} | ||
|
||
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] | ||
#[serde(tag = "q")] | ||
pub enum Request { | ||
#[allow(non_camel_case_types)] | ||
get_nodes, | ||
|
||
#[allow(non_camel_case_types)] | ||
get_amount, | ||
|
||
#[allow(non_camel_case_types)] | ||
get_transaction, | ||
} | ||
|
||
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] | ||
#[serde(tag = "r")] | ||
pub enum Response { | ||
#[allow(non_camel_case_types)] | ||
get_nodes(GetNodesReponse), | ||
|
||
#[allow(non_camel_case_types)] | ||
get_amount(GetAmountReponse), | ||
|
||
#[allow(non_camel_case_types)] | ||
get_transaction(GetTransactionResponse), | ||
} | ||
|
||
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] | ||
pub struct ErrorR { | ||
code: ErrorCode, | ||
} | ||
|
||
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] | ||
pub struct GetNodesReponse { | ||
ipv4: Option<Vec<u8>>, | ||
ipv6: Option<Vec<u8>>, | ||
} | ||
|
||
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] | ||
pub struct GetAmountReponse { | ||
amount: Option<Vec<u8>>, | ||
} | ||
|
||
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] | ||
pub struct GetTransactionResponse { | ||
transaction: Vec<u8>, | ||
} | ||
|
||
#[cfg(test)] | ||
mod packet_tests { | ||
use super::*; | ||
use rmp_serde::{Deserializer, Serializer}; | ||
use std::io::Cursor; | ||
|
||
#[test] | ||
fn test_error() { | ||
let mut buf: Vec<u8> = Vec::new(); | ||
|
||
let obj = Packet::error(ErrorR { | ||
code: ErrorCode::ParseError, | ||
}); | ||
|
||
#[derive(Debug, PartialEq, Deserialize, Serialize)] | ||
#[serde(tag = "r")] | ||
pub enum Response{ | ||
#[allow(non_camel_case_types)] | ||
get_nodes(GetNodesReponse), | ||
obj.serialize(&mut Serializer::new(&mut buf)).unwrap(); | ||
|
||
#[allow(non_camel_case_types)] | ||
get_amount(GetAmountReponse), | ||
let deserialized = | ||
Packet::deserialize(&mut Deserializer::new(Cursor::new(buf))).unwrap(); | ||
|
||
#[allow(non_camel_case_types)] | ||
get_transaction(GetTransactionResponse) | ||
assert_eq!(obj, deserialized); | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug, PartialEq, Deserialize, Serialize)] | ||
pub struct ErrorR{ | ||
code:ErrorCode | ||
pub mod peers_dump { | ||
use super::*; | ||
|
||
#[derive(Debug, Deserialize, Serialize)] | ||
pub struct Peers { | ||
ipv4: Option<Vec<u8>>, | ||
ipv6: Option<Vec<u8>>, | ||
} | ||
} | ||
|
||
pub fn dump_addresses(addrs: &[SocketAddr]) -> (Vec<u8>, Vec<u8>) { | ||
let mut ipv4: Vec<u8> = Vec::new(); | ||
let mut ipv6: Vec<u8> = Vec::new(); | ||
|
||
for addr in addrs { | ||
let port = addr.port(); | ||
match addr.ip() { | ||
IpAddr::V4(ip) => { | ||
for byte in ip.octets() { | ||
ipv4.push(byte); | ||
} | ||
ipv4.push((port >> 8) as u8); | ||
ipv4.push(port as u8); | ||
} | ||
IpAddr::V6(ip) => { | ||
for byte in ip.octets() { | ||
ipv6.push(byte); | ||
} | ||
ipv6.push((port >> 8) as u8); | ||
ipv6.push(port as u8); | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug, PartialEq, Deserialize, Serialize)] | ||
pub struct GetNodesReponse{ | ||
ipv4: Option<Vec<u8>>, | ||
ipv6: Option<Vec<u8>> | ||
(ipv4, ipv6) | ||
} | ||
|
||
#[derive(Debug, PartialEq, Deserialize, Serialize)] | ||
pub struct GetAmountReponse{ | ||
ipv4: Option<Vec<u8>> | ||
pub fn parse_ipv4(data: &[u8]) -> Result<Vec<SocketAddr>> { | ||
if data.len() % 6 != 0 { | ||
return Err(models_errors::WrongSizeIPv4.into()); | ||
} | ||
let mut to_return: Vec<SocketAddr> = Vec::with_capacity(data.len() / 6); | ||
|
||
for index in (0..data.len()).step_by(6) { | ||
let port: u16 = data[index + 5] as u16 + ((data[index + 4] as u16) << 8); | ||
let addr = SocketAddr::new( | ||
IpAddr::V4(Ipv4Addr::new( | ||
data[index], | ||
data[index + 1], | ||
data[index + 2], | ||
data[index + 3], | ||
)), | ||
port, | ||
); | ||
to_return.push(addr); | ||
} | ||
|
||
Ok(to_return) | ||
} | ||
|
||
#[derive(Debug, PartialEq, Deserialize, Serialize)] | ||
pub struct GetTransactionResponse{ | ||
transaction: Vec<u8> | ||
pub fn parse_ipv6(data: &[u8]) -> Result<Vec<SocketAddr>> { | ||
if data.len() % 18 != 0 { | ||
return Err(models_errors::WrongSizeIPv6.into()); | ||
} | ||
let mut to_return: Vec<SocketAddr> = Vec::with_capacity(data.len() / 18); | ||
|
||
for index in (0..data.len()).step_by(18) { | ||
let port: u16 = data[index + 17] as u16 + ((data[index + 16] as u16) << 8); | ||
let octets: [u8; 16] = data[index..index + 16].try_into()?; | ||
let addr = SocketAddr::new(IpAddr::V6(Ipv6Addr::from(octets)), port); | ||
to_return.push(addr); | ||
} | ||
|
||
Ok(to_return) | ||
} | ||
|
||
#[cfg(test)] | ||
mod packet_tests{ | ||
mod dump_parse_tests { | ||
use super::*; | ||
use rmp_serde::{Deserializer, Serializer}; | ||
use std::io::Cursor; | ||
|
||
#[test] | ||
fn test_error(){ | ||
let mut buf:Vec<u8> = Vec::new(); | ||
fn dump_addresses_test() { | ||
let expected_ipv6 = | ||
b"\xfe\x80\xcd\x00\x00\x00\x0c\xde\x12\x57\x00\x00\x21\x1e\x72\x9c\x00\xff"; | ||
let expected_ipv4 = b"\x7f\x00\x00\x01\x00\xff"; | ||
let mut input: Vec<SocketAddr> = Vec::with_capacity(2); | ||
|
||
input.push( | ||
"[FE80:CD00:0000:0CDE:1257:0000:211E:729C]:255" | ||
.parse() | ||
.unwrap(), | ||
); | ||
input.push("127.0.0.1:255".parse().unwrap()); | ||
|
||
let (ipv4, ipv6) = dump_addresses(&input); | ||
|
||
assert_eq!(expected_ipv4, ipv4.as_slice()); | ||
|
||
assert_eq!(expected_ipv6, ipv6.as_slice()); | ||
} | ||
|
||
#[test] | ||
fn parse_ipv4_test() { | ||
let mut expected: Vec<SocketAddr> = Vec::with_capacity(2); | ||
|
||
expected.push("127.0.0.1:255".parse().unwrap()); | ||
expected.push("127.0.0.1:255".parse().unwrap()); | ||
|
||
let dump_ipv4 = b"\x7f\x00\x00\x01\x00\xff\x7f\x00\x00\x01\x00\xff"; | ||
|
||
let result = parse_ipv4(dump_ipv4).unwrap(); | ||
|
||
assert_eq!(result, expected); | ||
} | ||
|
||
#[test] | ||
fn parse_ipv6_test() { | ||
let mut expected: Vec<SocketAddr> = Vec::with_capacity(2); | ||
|
||
let obj = Packet::error(ErrorR{code:ErrorCode::ParseError}); | ||
expected.push( | ||
"[FE80:CD00:0000:0CDE:1257:0000:211E:729C]:255" | ||
.parse() | ||
.unwrap(), | ||
); | ||
expected.push( | ||
"[FE80:CD00:0000:0CDE:1257:0000:211E:729C]:255" | ||
.parse() | ||
.unwrap(), | ||
); | ||
|
||
obj.serialize(&mut Serializer::new(&mut buf)).unwrap(); | ||
let dump_ipv6 = b"\xfe\x80\xcd\x00\x00\x00\x0c\xde\x12\x57\x00\x00\x21\x1e\x72\x9c\x00\xff\xfe\x80\xcd\x00\x00\x00\x0c\xde\x12\x57\x00\x00\x21\x1e\x72\x9c\x00\xff"; | ||
|
||
let deserialized = Packet::deserialize(&mut Deserializer::new(Cursor::new(buf))).unwrap(); | ||
let result = parse_ipv6(dump_ipv6).unwrap(); | ||
|
||
assert_eq!(obj,deserialized); | ||
assert_eq!(result, expected); | ||
} | ||
} |
Oops, something went wrong.