Commit 6e1af891 authored by 神楽坂玲奈's avatar 神楽坂玲奈

init

parents
/target
/import
\ No newline at end of file
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/railgun-routing-client.iml" filepath="$PROJECT_DIR$/.idea/railgun-routing-client.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module type="CPP_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
\ No newline at end of file
This diff is collapsed.
[package]
name = "railgun-routing-client"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
config = "0.13.1"
lazy_static = "1.4.0"
average = "0.13.1"
serde_json = "1.0"
serde = "1.0.159"
tokio = { version = "1", features = ["full"] }
{
"id": 99,
"server": "43.142.53.161:500",
"port": 495,
"timeout": 10,
"history": 100,
"interval": 1000,
"table": 2000,
"proto": 250
}
use serde::Deserialize;
use std::collections::HashSet;
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Router {
pub id: u8,
pub name: String,
pub address: String,
pub location: String,
pub user: String,
pub host: String,
pub ssh_port: u16,
pub ssh_system: Option<u16>,
pub next_mark: u16,
pub dest_mark: u16,
pub port: u16,
pub port2: u16,
pub wg_private_key: Option<String>,
pub masq_interfaces: Vec<String>,
pub os: String,
pub arch: String,
pub ocserv_port: u16,
pub offset: u16,
pub offset2: u16,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GatewayGroup {
pub id: u16,
pub name: String,
pub description: String,
pub children: HashSet<String>,
pub dest_mark: u16,
pub location_prefix: Vec<String>,
pub include_routers: HashSet<String>,
pub exclude_routers: HashSet<String>,
}
use std::collections::{HashMap, HashSet};
use crate::data::{GatewayGroup, Router};
impl GatewayGroup {
pub fn routers(&self, groups: &Vec<GatewayGroup>, routers: &Vec<Router>) -> HashSet<u8> {
return routers
.iter()
.filter(|r| self.include_routers.contains(&r.name))
.chain(
self.location_prefix
.iter()
.flat_map(|p| routers.iter().filter(move |r| r.location.starts_with(p))),
)
.filter(|r| !self.exclude_routers.contains(&r.name))
.map(|r| r.id)
.chain(
groups
.iter()
.filter(|g| self.children.contains(&g.name))
.flat_map(|g1| g1.routers(groups, routers)),
)
.collect();
}
}
use std::collections::{HashMap, HashSet};
use std::fs;
use std::net::{IpAddr, SocketAddr};
use std::time::SystemTime;
use tokio::net::UdpSocket;
use tokio::time;
use crate::data::{GatewayGroup, Router as RouterData};
use crate::protocol::{Change, Hello};
use crate::router::Router;
use crate::server::Server;
use crate::settings::CONFIG;
mod data;
mod gateway_group;
mod protocol;
mod route_writer;
mod router;
mod server;
mod settings;
#[tokio::main]
async fn main() {
let routers_data =
serde_json::from_slice::<Vec<RouterData>>(&fs::read("import/Router.json").unwrap())
.unwrap();
let groups: Vec<GatewayGroup> =
serde_json::from_slice(&fs::read("import/GatewayGroup.json").unwrap()).unwrap();
let mut routers: HashMap<u8, Router> =
serde_json::from_slice::<Vec<RouterData>>(&fs::read("import/Router.json").unwrap())
.unwrap()
.iter()
.map(|r| (r.id, Router::new(r)))
.collect();
let mut server = Server::new(
&routers,
groups
.iter()
.map(|g| (g.id, g.routers(&groups, &routers_data)))
.collect::<HashMap<u16, HashSet<u8>>>(),
);
let mut self_peer = Hello {
id: CONFIG.id,
seq: 0,
time: 0,
};
let socket = UdpSocket::bind(SocketAddr::new(IpAddr::from([0, 0, 0, 0]), CONFIG.port))
.await
.unwrap();
let mut timer = time::interval(time::Duration::from_millis(CONFIG.interval));
let mut buf = [0; 1500];
loop {
tokio::select! {
result = socket.recv_from(&mut buf) => {
let (_, src) = result.unwrap();
if src == CONFIG.server {
// from server
let message: Change = serde_json::from_slice(&buf).unwrap();
server.on_message(&socket, &message, &mut routers, &self_peer);
} else {
// from client
let message: Hello = serde_json::from_slice(&buf).unwrap();
let peer = routers.get_mut(&message.id).unwrap();
assert_eq!(src, peer.link_address);
peer.on_message(&message);
}
}
_ = timer.tick() => {
self_peer.time = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_millis() as u64;
let message = serde_json::to_vec(&self_peer).unwrap();
for peer in routers.values() {
let _ = socket.send_to(message.as_slice(), peer.link_address);
}
let _ = server.update(&socket, &mut routers, &self_peer);
self_peer.seq += 1;
}
}
}
}
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct Hello {
pub id: u8,
pub seq: u32,
pub time: u64,
}
#[derive(Serialize, Deserialize)]
pub struct Change {
pub seq: u32,
pub via: HashMap<u8, u8>,
pub plan: HashMap<u8, u8>,
}
#[derive(Serialize, Deserialize)]
pub struct PeerQuality {
pub delay: f64,
pub jitter: f64,
pub reliability: f64,
}
#[derive(Serialize, Deserialize)]
pub struct Report {
pub id: u8,
pub ack: u32,
pub peers: Option<HashMap<u8, PeerQuality>>,
}
use std::collections::HashMap;
struct RouteWriter {
via: HashMap<u8, u8>,
plan: HashMap<u16, u8>,
}
impl RouteWriter {
fn new() -> Self {
Self {
via: HashMap::new(),
plan: HashMap::new(),
}
}
fn set_via(&mut self, to: u8, via: u8) {
self.via.insert(to, via);
}
fn set_plan(&mut self, group: u16, to: u8) {
self.plan.insert(group, to);
}
fn commit(&mut self) {
// self.via.clear();
// self.plan.clear();
}
}
use std::net::{IpAddr, SocketAddr};
use std::time::SystemTime;
use average::Mean;
use crate::data::Router as RouterData;
use crate::protocol::{Hello, PeerQuality};
use crate::settings::CONFIG;
pub struct Router {
address: String,
pub link_address: SocketAddr,
subnets: Vec<String>,
delay: f64,
jitter: f64,
reliability: f64,
seq: u32,
time: u64,
history: Vec<Option<u64>>,
}
impl Router {
pub fn new(data: &RouterData) -> Router {
Router {
address: String::from(""),
link_address: SocketAddr::new(IpAddr::from([10, 200, data.id, CONFIG.id]), CONFIG.port),
subnets: Vec::new(),
delay: 0.0,
jitter: 0.0,
reliability: 0.0,
seq: 0,
time: 0,
history: Vec::new(),
}
}
pub fn reset(&mut self) {
self.delay = 0.0;
self.jitter = 0.0;
self.reliability = 0.0;
self.seq = 0;
self.time = 0;
}
pub fn on_message(&mut self, data: &Hello) {
if data.seq == 0
|| data.seq < self.seq - CONFIG.timeout
|| data.seq > self.seq + CONFIG.timeout
{
// 收到 seq = 0 或 seq 与之前差距较大,就 reset
self.reset();
self.seq = data.seq - 1;
} else if data.seq <= self.seq {
// 收到 seq 比已知略小的,忽略
return;
}
let time = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_millis() as u64;
let step = data.seq - self.seq;
let delay = time - data.time;
for _ in 0..step - 1 {
self.history.push(None);
}
self.history.push(Some(delay));
self.history
.splice(0..self.history.len() - CONFIG.history, []);
let history: Vec<u64> = self
.history
.iter()
.filter(|s| s.is_some())
.map(|s| s.unwrap())
.collect();
self.reliability = history.len() as f64 / CONFIG.history as f64;
self.delay = history.iter().sum::<u64>() as f64 / history.len() as f64;
self.jitter = (0..history.len() - 1)
.map(|i| (history[i] - history[i + 1]) as f64)
.collect::<Mean>()
.mean();
self.seq = data.seq;
self.time = time;
}
pub(crate) fn update(&mut self, time: u64) -> PeerQuality {
if self.reliability > 0.0 {
// 有几个包没到
let step = ((time - self.time) / CONFIG.interval) as u32;
if step > CONFIG.timeout {
self.reset();
}
}
let lost = (time - self.time) / CONFIG.interval - 2;
let reliability = f64::max(0.0, self.reliability - lost as f64 / CONFIG.history as f64);
PeerQuality {
delay: self.delay,
jitter: self.jitter,
reliability,
}
}
}
use std::collections::{HashMap, HashSet};
use tokio::net::UdpSocket;
use crate::data::GatewayGroup;
use crate::protocol::{Change, Hello, Report};
use crate::router::Router;
use crate::settings::CONFIG;
pub struct Server {
ack: u32,
groups: HashMap<u16, HashSet<u8>>,
}
impl Server {
pub fn new(routers: &HashMap<u8, Router>, groups: HashMap<u16, HashSet<u8>>) -> Self {
Server { ack: 0, groups }
}
pub fn on_message(
&mut self,
socket: &UdpSocket,
message: &Change,
routers: &mut HashMap<u8, Router>,
self_peer: &Hello,
) {
if message.seq == 0 {
self.ack = 0;
// RouteWriter::reset();
}
if self.ack != message.seq {
println!(
"seq mismatch rejected, server seq={}, local ack={}",
message.seq, self.ack
);
return;
}
for (to, via) in message.via.iter() {
// RouteWriter::set_via(*to, *via);
}
// if let Some(plan) = message.plan.as_ref() {
for (group_id, to) in message.plan.iter() {
// RouteWriter::set_plan(&GatewayGroup::all()[*group_id], *to);
}
// }
// RouteWriter::commit();
self.ack += 1;
self.update(socket, routers, self_peer);
}
pub fn update(
&mut self,
socket: &UdpSocket,
routers: &mut HashMap<u8, Router>,
self_peer: &Hello,
) {
let data = Report {
id: self_peer.id,
ack: self.ack,
peers: Some(
routers
.into_iter()
.map(|(&id, peer)| (id, peer.update(self_peer.time)))
.collect(),
),
};
let message = serde_json::to_vec(&data).unwrap();
let _ = socket.send_to(message.as_slice(), CONFIG.server);
}
}
use std::net::SocketAddr;
use config::Config;
use lazy_static::lazy_static;
use serde::Deserialize;
#[derive(Deserialize)]
pub struct Settings {
pub id: u8,
pub server: SocketAddr,
pub port: u16,
pub timeout: u32,
pub history: usize,
pub interval: u64,
pub table: u16,
pub proto: u16,
}
lazy_static! {
pub static ref CONFIG: Settings = Config::builder()
.add_source(config::File::with_name("config/config.json"))
.add_source(config::Environment::with_prefix("RAILGUN"))
.build()
.unwrap()
.try_deserialize()
.unwrap();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment