mirror of https://github.com/dswd/vpncloud.git
Lots of changes
This commit is contained in:
parent
f559e9bf09
commit
d9dedcdd0d
|
@ -10,7 +10,6 @@ docopt = "0.6"
|
|||
rustc-serialize = "0.3"
|
||||
log = "0.3"
|
||||
epoll = "0.2"
|
||||
regex = "0.1"
|
||||
|
||||
[build-dependencies]
|
||||
gcc = "0.3"
|
||||
|
|
57
src/cloud.rs
57
src/cloud.rs
|
@ -18,15 +18,21 @@ use super::ip::{InternetProtocol, IpAddress, RoutingTable};
|
|||
|
||||
pub type NetworkId = u64;
|
||||
|
||||
pub trait Address: Sized + fmt::Debug + Clone {
|
||||
fn from_bytes(&[u8]) -> Result<Self, Error>;
|
||||
fn to_bytes(&self) -> Vec<u8>;
|
||||
}
|
||||
|
||||
pub trait Table {
|
||||
type Address;
|
||||
type Address: Address;
|
||||
fn learn(&mut self, Self::Address, SocketAddr);
|
||||
fn lookup(&self, &Self::Address) -> Option<SocketAddr>;
|
||||
fn housekeep(&mut self);
|
||||
fn remove_all(&mut self, SocketAddr);
|
||||
}
|
||||
|
||||
pub trait Protocol: Sized {
|
||||
type Address;
|
||||
type Address: Address;
|
||||
fn parse(&[u8]) -> Result<(Self::Address, Self::Address), Error>;
|
||||
}
|
||||
|
||||
|
@ -113,8 +119,10 @@ impl PeerList {
|
|||
}
|
||||
|
||||
|
||||
pub struct GenericCloud<A, T: Table<Address=A>, M: Protocol<Address=A>, I: VirtualInterface> {
|
||||
pub struct GenericCloud<A: Address, T: Table<Address=A>, M: Protocol<Address=A>, I: VirtualInterface> {
|
||||
peers: PeerList,
|
||||
addresses: Vec<A>,
|
||||
learning: bool,
|
||||
reconnect_peers: Vec<SocketAddr>,
|
||||
table: T,
|
||||
socket: UdpSocket,
|
||||
|
@ -127,14 +135,17 @@ pub struct GenericCloud<A, T: Table<Address=A>, M: Protocol<Address=A>, I: Virtu
|
|||
_dummy_m: PhantomData<M>,
|
||||
}
|
||||
|
||||
impl<A: fmt::Debug, T: Table<Address=A>, M: Protocol<Address=A>, I: VirtualInterface> GenericCloud<A, T, M, I> {
|
||||
pub fn new(device: I, listen: String, network_id: Option<NetworkId>, table: T, peer_timeout: Duration) -> Self {
|
||||
impl<A: Address, T: Table<Address=A>, M: Protocol<Address=A>, I: VirtualInterface> GenericCloud<A, T, M, I> {
|
||||
pub fn new(device: I, listen: String, network_id: Option<NetworkId>, table: T,
|
||||
peer_timeout: Duration, learning: bool, addresses: Vec<A>) -> Self {
|
||||
let socket = match UdpSocket::bind(&listen as &str) {
|
||||
Ok(socket) => socket,
|
||||
_ => panic!("Failed to open socket")
|
||||
};
|
||||
GenericCloud{
|
||||
peers: PeerList::new(peer_timeout),
|
||||
addresses: addresses,
|
||||
learning: learning,
|
||||
reconnect_peers: Vec::new(),
|
||||
table: table,
|
||||
socket: socket,
|
||||
|
@ -148,7 +159,7 @@ impl<A: fmt::Debug, T: Table<Address=A>, M: Protocol<Address=A>, I: VirtualInter
|
|||
}
|
||||
}
|
||||
|
||||
fn send_msg<Addr: ToSocketAddrs+fmt::Display>(&mut self, addr: Addr, msg: &Message) -> Result<(), Error> {
|
||||
fn send_msg<Addr: ToSocketAddrs+fmt::Display>(&mut self, addr: Addr, msg: &Message<A>) -> Result<(), Error> {
|
||||
debug!("Sending {:?} to {}", msg, addr);
|
||||
let mut options = Options::default();
|
||||
options.network_id = self.network_id;
|
||||
|
@ -176,7 +187,8 @@ impl<A: fmt::Debug, T: Table<Address=A>, M: Protocol<Address=A>, I: VirtualInter
|
|||
let addr = addr.to_socket_addrs().unwrap().next().unwrap();
|
||||
self.reconnect_peers.push(addr);
|
||||
}
|
||||
self.send_msg(addr, &Message::GetPeers)
|
||||
let addrs = self.addresses.clone();
|
||||
self.send_msg(addr, &Message::Init(addrs))
|
||||
}
|
||||
|
||||
fn housekeep(&mut self) -> Result<(), Error> {
|
||||
|
@ -211,11 +223,15 @@ impl<A: fmt::Debug, T: Table<Address=A>, M: Protocol<Address=A>, I: VirtualInter
|
|||
match self.table.lookup(&dst) {
|
||||
Some(addr) => {
|
||||
debug!("Found destination for {:?} => {}", dst, addr);
|
||||
try!(self.send_msg(addr, &Message::Frame(payload)))
|
||||
if self.peers.contains(&addr) {
|
||||
try!(self.send_msg(addr, &Message::Data(payload)))
|
||||
} else {
|
||||
warn!("Destination for {:?} not found in peers: {}", dst, addr);
|
||||
}
|
||||
},
|
||||
None => {
|
||||
debug!("No destination for {:?} found, broadcasting", dst);
|
||||
let msg = Message::Frame(payload);
|
||||
let msg = Message::Data(payload);
|
||||
for addr in &self.peers.as_vec() {
|
||||
try!(self.send_msg(addr, &msg));
|
||||
}
|
||||
|
@ -224,7 +240,7 @@ impl<A: fmt::Debug, T: Table<Address=A>, M: Protocol<Address=A>, I: VirtualInter
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_net_message(&mut self, peer: SocketAddr, options: Options, msg: Message) -> Result<(), Error> {
|
||||
fn handle_net_message(&mut self, peer: SocketAddr, options: Options, msg: Message<A>) -> Result<(), Error> {
|
||||
if let Some(id) = self.network_id {
|
||||
if options.network_id != Some(id) {
|
||||
info!("Ignoring message from {} with wrong token {:?}", peer, options.network_id);
|
||||
|
@ -233,18 +249,20 @@ impl<A: fmt::Debug, T: Table<Address=A>, M: Protocol<Address=A>, I: VirtualInter
|
|||
}
|
||||
debug!("Recieved {:?} from {}", msg, peer);
|
||||
match msg {
|
||||
Message::Frame(payload) => {
|
||||
Message::Data(payload) => {
|
||||
let (src, _dst) = try!(M::parse(payload));
|
||||
debug!("Writing data to device: {} bytes", payload.len());
|
||||
match self.device.write(&payload) {
|
||||
Ok(()) => (),
|
||||
Err(e) => {
|
||||
error!("Failed to send via tap device {:?}", e);
|
||||
return Err(Error::TunTapDevError("Failed to write to tap device"));
|
||||
error!("Failed to send via device {:?}", e);
|
||||
return Err(Error::TunTapDevError("Failed to write to device"));
|
||||
}
|
||||
}
|
||||
self.peers.add(&peer);
|
||||
if self.learning {
|
||||
self.table.learn(src, peer);
|
||||
}
|
||||
},
|
||||
Message::Peers(peers) => {
|
||||
self.peers.add(&peer);
|
||||
|
@ -254,10 +272,13 @@ impl<A: fmt::Debug, T: Table<Address=A>, M: Protocol<Address=A>, I: VirtualInter
|
|||
}
|
||||
}
|
||||
},
|
||||
Message::GetPeers => {
|
||||
Message::Init(addrs) => {
|
||||
self.peers.add(&peer);
|
||||
let peers = self.peers.as_vec();
|
||||
try!(self.send_msg(peer, &Message::Peers(peers)));
|
||||
for addr in addrs {
|
||||
self.table.learn(addr, peer.clone());
|
||||
}
|
||||
},
|
||||
Message::Close => {
|
||||
self.peers.remove(&peer);
|
||||
|
@ -323,7 +344,7 @@ impl TapCloud {
|
|||
};
|
||||
info!("Opened tap device {}", device.ifname());
|
||||
let table = MacTable::new(mac_timeout);
|
||||
Self::new(device, listen, network_id, table, peer_timeout)
|
||||
Self::new(device, listen, network_id, table, peer_timeout, true, vec![])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -331,12 +352,14 @@ impl TapCloud {
|
|||
pub type TunCloud = GenericCloud<IpAddress, RoutingTable, InternetProtocol, TunDevice>;
|
||||
|
||||
impl TunCloud {
|
||||
pub fn new_tun_cloud(device: &str, listen: String, network_id: Option<NetworkId>, table: RoutingTable, peer_timeout: Duration) -> Self {
|
||||
pub fn new_tun_cloud(device: &str, listen: String, network_id: Option<NetworkId>, subnet: String, peer_timeout: Duration) -> Self {
|
||||
let device = match TunDevice::new(device) {
|
||||
Ok(device) => device,
|
||||
_ => panic!("Failed to open tun device")
|
||||
};
|
||||
info!("Opened tun device {}", device.ifname());
|
||||
Self::new(device, listen, network_id, table, peer_timeout)
|
||||
let table = RoutingTable::new();
|
||||
let subnet = IpAddress::from_str(&subnet).expect("Invalid subnet");
|
||||
Self::new(device, listen, network_id, table, peer_timeout, false, vec![subnet])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::net::SocketAddr;
|
|||
use std::collections::HashMap;
|
||||
use std::io::Write;
|
||||
|
||||
use super::cloud::{Error, Table, Protocol};
|
||||
use super::cloud::{Error, Table, Protocol, Address};
|
||||
use super::util::as_obj;
|
||||
|
||||
use time::{Duration, SteadyTime};
|
||||
|
@ -27,6 +27,16 @@ pub struct EthAddr {
|
|||
pub vlan: Option<VlanId>
|
||||
}
|
||||
|
||||
impl Address for EthAddr {
|
||||
fn from_bytes(_bytes: &[u8]) -> Result<Self, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn to_bytes(&self) -> Vec<u8> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub struct Frame;
|
||||
|
@ -103,6 +113,10 @@ impl Table for MacTable {
|
|||
None => None
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_all(&mut self, _addr: SocketAddr) {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
147
src/ip.rs
147
src/ip.rs
|
@ -1,25 +1,23 @@
|
|||
use std::net::{SocketAddr, Ipv4Addr, Ipv6Addr, AddrParseError, ToSocketAddrs};
|
||||
use std::net::{SocketAddr, Ipv4Addr, Ipv6Addr};
|
||||
use std::collections::{hash_map, HashMap};
|
||||
use std::ptr;
|
||||
use std::path::Path;
|
||||
use std::fs::File;
|
||||
use std::io::{Result as IoResult, Read, BufRead, BufReader};
|
||||
use std::io::Read;
|
||||
use std::str::FromStr;
|
||||
|
||||
use regex::Regex;
|
||||
|
||||
use super::cloud::{Protocol, Error, Table};
|
||||
use super::cloud::{Protocol, Error, Table, Address};
|
||||
use super::util::{as_obj, as_bytes};
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum IpAddress {
|
||||
V4(Ipv4Addr),
|
||||
V6(Ipv6Addr)
|
||||
V6(Ipv6Addr),
|
||||
V4Net(Ipv4Addr, u8),
|
||||
V6Net(Ipv6Addr, u8),
|
||||
}
|
||||
|
||||
impl IpAddress {
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
impl Address for IpAddress {
|
||||
fn to_bytes(&self) -> Vec<u8> {
|
||||
match self {
|
||||
&IpAddress::V4(addr) => {
|
||||
let ip = addr.octets();
|
||||
|
@ -30,6 +28,11 @@ impl IpAddress {
|
|||
}
|
||||
res
|
||||
},
|
||||
&IpAddress::V4Net(addr, prefix_len) => {
|
||||
let mut bytes = IpAddress::V4(addr).to_bytes();
|
||||
bytes.push(prefix_len);
|
||||
bytes
|
||||
},
|
||||
&IpAddress::V6(addr) => {
|
||||
let mut segments = addr.segments();
|
||||
for i in 0..8 {
|
||||
|
@ -42,14 +45,56 @@ impl IpAddress {
|
|||
ptr::copy_nonoverlapping(bytes.as_ptr(), res.as_mut_ptr(), bytes.len());
|
||||
}
|
||||
res
|
||||
},
|
||||
&IpAddress::V6Net(addr, prefix_len) => {
|
||||
let mut bytes = IpAddress::V6(addr).to_bytes();
|
||||
bytes.push(prefix_len);
|
||||
bytes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(addr: &str) -> Result<Self, AddrParseError> {
|
||||
fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
|
||||
match bytes.len() {
|
||||
4 => Ok(IpAddress::V4(Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3]))),
|
||||
5 => Ok(IpAddress::V4Net(Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3]), bytes[4])),
|
||||
16 => {
|
||||
let data = unsafe { as_obj::<[u16; 8]>(&bytes) };
|
||||
Ok(IpAddress::V6(Ipv6Addr::new(
|
||||
u16::from_be(data[0]), u16::from_be(data[1]),
|
||||
u16::from_be(data[2]), u16::from_be(data[3]),
|
||||
u16::from_be(data[4]), u16::from_be(data[5]),
|
||||
u16::from_be(data[6]), u16::from_be(data[7]),
|
||||
)))
|
||||
},
|
||||
17 => {
|
||||
let data = unsafe { as_obj::<[u16; 8]>(&bytes) };
|
||||
Ok(IpAddress::V6Net(Ipv6Addr::new(
|
||||
u16::from_be(data[0]), u16::from_be(data[1]),
|
||||
u16::from_be(data[2]), u16::from_be(data[3]),
|
||||
u16::from_be(data[4]), u16::from_be(data[5]),
|
||||
u16::from_be(data[6]), u16::from_be(data[7]),
|
||||
), bytes[16]))
|
||||
}
|
||||
_ => Err(Error::ParseError("Invalid address size"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IpAddress {
|
||||
pub fn from_str(addr: &str) -> Result<Self, Error> {
|
||||
if let Some(pos) = addr.find("/") {
|
||||
let prefix_len = try!(u8::from_str(&addr[pos+1..])
|
||||
.map_err(|_| Error::ParseError("Failed to parse prefix length")));
|
||||
let addr = &addr[..pos];
|
||||
let ipv4 = Ipv4Addr::from_str(addr).map(|addr| IpAddress::V4Net(addr, prefix_len));
|
||||
let ipv6 = Ipv6Addr::from_str(addr).map(|addr| IpAddress::V6Net(addr, prefix_len));
|
||||
ipv4.or(ipv6).map_err(|_| Error::ParseError("Failed to parse address"))
|
||||
} else {
|
||||
let ipv4 = Ipv4Addr::from_str(addr).map(|addr| IpAddress::V4(addr));
|
||||
let ipv6 = Ipv6Addr::from_str(addr).map(|addr| IpAddress::V6(addr));
|
||||
ipv4.or(ipv6)
|
||||
ipv4.or(ipv6).map_err(|_| Error::ParseError("Failed to parse address"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,31 +114,13 @@ impl Protocol for InternetProtocol {
|
|||
if data.len() < 20 {
|
||||
return Err(Error::ParseError("Truncated header"));
|
||||
}
|
||||
let src_data = unsafe { as_obj::<[u8; 4]>(&data[12..]) };
|
||||
let src = Ipv4Addr::new(src_data[0], src_data[1], src_data[2], src_data[3]);
|
||||
let dst_data = unsafe { as_obj::<[u8; 4]>(&data[16..]) };
|
||||
let dst = Ipv4Addr::new(dst_data[0], dst_data[1], dst_data[2], dst_data[3]);
|
||||
Ok((IpAddress::V4(src), IpAddress::V4(dst)))
|
||||
Ok((try!(IpAddress::from_bytes(&data[12..16])), try!(IpAddress::from_bytes(&data[16..20]))))
|
||||
},
|
||||
6 => {
|
||||
if data.len() < 40 {
|
||||
return Err(Error::ParseError("Truncated header"));
|
||||
}
|
||||
let src_data = unsafe { as_obj::<[u16; 8]>(&data[8..]) };
|
||||
let src = Ipv6Addr::new(
|
||||
u16::from_be(src_data[0]), u16::from_be(src_data[1]),
|
||||
u16::from_be(src_data[2]), u16::from_be(src_data[3]),
|
||||
u16::from_be(src_data[4]), u16::from_be(src_data[5]),
|
||||
u16::from_be(src_data[6]), u16::from_be(src_data[7]),
|
||||
);
|
||||
let dst_data = unsafe { as_obj::<[u16; 8]>(&data[24..]) };
|
||||
let dst = Ipv6Addr::new(
|
||||
u16::from_be(dst_data[0]), u16::from_be(dst_data[1]),
|
||||
u16::from_be(dst_data[2]), u16::from_be(dst_data[3]),
|
||||
u16::from_be(dst_data[4]), u16::from_be(dst_data[5]),
|
||||
u16::from_be(dst_data[6]), u16::from_be(dst_data[7]),
|
||||
);
|
||||
Ok((IpAddress::V6(src), IpAddress::V6(dst)))
|
||||
Ok((try!(IpAddress::from_bytes(&data[8..24])), try!(IpAddress::from_bytes(&data[24..40]))))
|
||||
},
|
||||
_ => Err(Error::ParseError("Invalid version"))
|
||||
}
|
||||
|
@ -125,49 +152,6 @@ impl RoutingTable {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn load_from(&mut self, path: &Path) -> IoResult<()> {
|
||||
let pattern = Regex::new(r"(?P<base>[^/]+)/(?P<prefix>\d+)\s=>\s(?P<peer>.+)").unwrap();
|
||||
let file = try!(File::open(path));
|
||||
let mut reader = BufReader::new(file);
|
||||
loop {
|
||||
let mut s = String::new();
|
||||
let res = try!(reader.read_line(&mut s));
|
||||
if res == 0 {
|
||||
break;
|
||||
}
|
||||
let captures = match pattern.captures(&s) {
|
||||
Some(captures) => captures,
|
||||
None => {
|
||||
error!("Failed to parse routing table entry: {}", s);
|
||||
continue
|
||||
}
|
||||
};
|
||||
let base = match IpAddress::from_str(captures.name("base").unwrap()) {
|
||||
Ok(addr) => addr.to_bytes(),
|
||||
Err(e) => {
|
||||
error!("Failed to parse base address: {}", e);
|
||||
continue
|
||||
}
|
||||
};
|
||||
let prefix_len = match u8::from_str(captures.name("prefix").unwrap()) {
|
||||
Ok(num) => num,
|
||||
Err(e) => {
|
||||
error!("Failed to parse prefix length: {}", e);
|
||||
continue
|
||||
}
|
||||
};
|
||||
let peer = match captures.name("peer").unwrap().to_socket_addrs().map(|mut r| r.next()) {
|
||||
Ok(Some(addr)) => addr,
|
||||
_ => {
|
||||
error!("Failed to parse peer address");
|
||||
continue
|
||||
}
|
||||
};
|
||||
self.add(base, prefix_len, peer);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn lookup_bytes(&self, bytes: &[u8]) -> Option<SocketAddr> {
|
||||
let len = bytes.len()/2 * 2;
|
||||
for i in 0..len/2 {
|
||||
|
@ -199,8 +183,13 @@ impl RoutingTable {
|
|||
impl Table for RoutingTable {
|
||||
type Address = IpAddress;
|
||||
|
||||
fn learn(&mut self, _src: Self::Address, _addr: SocketAddr) {
|
||||
//nothing to do
|
||||
fn learn(&mut self, src: Self::Address, addr: SocketAddr) {
|
||||
match src {
|
||||
IpAddress::V4(_) => (),
|
||||
IpAddress::V4Net(base, prefix_len) => self.add(IpAddress::V4(base).to_bytes(), prefix_len, addr),
|
||||
IpAddress::V6(_) => (),
|
||||
IpAddress::V6Net(base, prefix_len) => self.add(IpAddress::V6(base).to_bytes(), prefix_len, addr)
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup(&self, dst: &Self::Address) -> Option<SocketAddr> {
|
||||
|
@ -210,4 +199,8 @@ impl Table for RoutingTable {
|
|||
fn housekeep(&mut self) {
|
||||
//nothin to do
|
||||
}
|
||||
|
||||
fn remove_all(&mut self, _addr: SocketAddr) {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
11
src/main.rs
11
src/main.rs
|
@ -3,7 +3,6 @@ extern crate time;
|
|||
extern crate docopt;
|
||||
extern crate rustc_serialize;
|
||||
extern crate epoll;
|
||||
extern crate regex;
|
||||
|
||||
mod util;
|
||||
mod udpmessage;
|
||||
|
@ -16,9 +15,7 @@ use time::Duration;
|
|||
use docopt::Docopt;
|
||||
|
||||
use std::hash::{Hash, SipHasher, Hasher};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use ip::RoutingTable;
|
||||
use cloud::{Error, TapCloud, TunCloud};
|
||||
|
||||
|
||||
|
@ -52,7 +49,7 @@ Options:
|
|||
-c <connect>, --connect <connect> List of peers (addr:port) to connect to
|
||||
--network-id <network_id> Optional token that identifies the network
|
||||
--peer-timeout <peer_timeout> Peer timeout in seconds [default: 1800]
|
||||
--table <file> The file containing the routing table (only for tun)
|
||||
--subnet <subnet> The local subnet to use (only for tun)
|
||||
--mac-timeout <mac_timeout> Mac table entry timeout in seconds (only for tap) [default: 300]
|
||||
-v, --verbose Log verbosely
|
||||
-q, --quiet Only print error messages
|
||||
|
@ -68,7 +65,7 @@ enum Type {
|
|||
#[derive(RustcDecodable, Debug)]
|
||||
struct Args {
|
||||
flag_type: Type,
|
||||
flag_table: PathBuf,
|
||||
flag_subnet: String,
|
||||
flag_device: String,
|
||||
flag_listen: String,
|
||||
flag_network_id: Option<String>,
|
||||
|
@ -98,8 +95,6 @@ fn tap_cloud(args: Args) {
|
|||
}
|
||||
|
||||
fn tun_cloud(args: Args) {
|
||||
let mut table = RoutingTable::new();
|
||||
table.load_from(&args.flag_table).unwrap();
|
||||
let mut tuncloud = TunCloud::new_tun_cloud(
|
||||
&args.flag_device,
|
||||
args.flag_listen,
|
||||
|
@ -108,7 +103,7 @@ fn tun_cloud(args: Args) {
|
|||
name.hash(&mut s);
|
||||
s.finish()
|
||||
}),
|
||||
table,
|
||||
args.flag_subnet,
|
||||
Duration::seconds(args.flag_peer_timeout as i64)
|
||||
);
|
||||
for addr in args.flag_connect {
|
||||
|
|
|
@ -2,8 +2,9 @@ use std::{mem, ptr, fmt};
|
|||
use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr};
|
||||
use std::u16;
|
||||
|
||||
use super::cloud::{Error, NetworkId};
|
||||
use super::cloud::{Error, NetworkId, Address};
|
||||
use super::util::{as_obj, as_bytes};
|
||||
use super::ethernet;
|
||||
|
||||
const MAGIC: [u8; 3] = [0x76, 0x70, 0x6e];
|
||||
const VERSION: u8 = 0;
|
||||
|
@ -30,17 +31,17 @@ pub struct Options {
|
|||
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum Message<'a> {
|
||||
Frame(&'a[u8]),
|
||||
pub enum Message<'a, A: Address> {
|
||||
Data(&'a[u8]),
|
||||
Peers(Vec<SocketAddr>),
|
||||
GetPeers,
|
||||
Init(Vec<A>),
|
||||
Close,
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for Message<'a> {
|
||||
impl<'a, A: Address> fmt::Debug for Message<'a, A> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match self {
|
||||
&Message::Frame(ref data) => write!(formatter, "Frame(data: {} bytes)", data.len()),
|
||||
&Message::Data(ref data) => write!(formatter, "Data(data: {} bytes)", data.len()),
|
||||
&Message::Peers(ref peers) => {
|
||||
try!(write!(formatter, "Peers ["));
|
||||
let mut first = true;
|
||||
|
@ -53,13 +54,13 @@ impl<'a> fmt::Debug for Message<'a> {
|
|||
}
|
||||
write!(formatter, "]")
|
||||
},
|
||||
&Message::GetPeers => write!(formatter, "GetPeers"),
|
||||
&Message::Init(ref data) => write!(formatter, "Init(data: {} bytes)", data.len()),
|
||||
&Message::Close => write!(formatter, "Close"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode(data: &[u8]) -> Result<(Options, Message), Error> {
|
||||
pub fn decode<A: Address>(data: &[u8]) -> Result<(Options, Message<A>), Error> {
|
||||
if data.len() < mem::size_of::<TopHeader>() {
|
||||
return Err(Error::ParseError("Empty message"));
|
||||
}
|
||||
|
@ -82,7 +83,7 @@ pub fn decode(data: &[u8]) -> Result<(Options, Message), Error> {
|
|||
pos += 8;
|
||||
}
|
||||
let msg = match header.msgtype {
|
||||
0 => Message::Frame(&data[pos..]),
|
||||
0 => Message::Data(&data[pos..]),
|
||||
1 => {
|
||||
if data.len() < pos + 1 {
|
||||
return Err(Error::ParseError("Empty peers"));
|
||||
|
@ -108,21 +109,41 @@ pub fn decode(data: &[u8]) -> Result<(Options, Message), Error> {
|
|||
}
|
||||
Message::Peers(peers)
|
||||
},
|
||||
2 => Message::GetPeers,
|
||||
2 => {
|
||||
if data.len() < pos + 1 {
|
||||
return Err(Error::ParseError("Init data too short"));
|
||||
}
|
||||
let count = data[pos] as usize;
|
||||
pos += 1;
|
||||
let mut addrs = Vec::with_capacity(count);
|
||||
for _ in 0..count {
|
||||
if data.len() < pos + 1 {
|
||||
return Err(Error::ParseError("Init data too short"));
|
||||
}
|
||||
let len = data[pos] as usize;
|
||||
pos += 1;
|
||||
if data.len() < pos + len {
|
||||
return Err(Error::ParseError("Init data too short"));
|
||||
}
|
||||
addrs.push(try!(A::from_bytes(&data[pos..pos+len])));
|
||||
pos += len;
|
||||
}
|
||||
Message::Init(addrs)
|
||||
},
|
||||
3 => Message::Close,
|
||||
_ => return Err(Error::ParseError("Unknown message type"))
|
||||
};
|
||||
Ok((options, msg))
|
||||
}
|
||||
|
||||
pub fn encode(options: &Options, msg: &Message, buf: &mut [u8]) -> usize {
|
||||
pub fn encode<A: Address>(options: &Options, msg: &Message<A>, buf: &mut [u8]) -> usize {
|
||||
assert!(buf.len() >= mem::size_of::<TopHeader>());
|
||||
let mut pos = 0;
|
||||
let mut header = TopHeader::default();
|
||||
header.msgtype = match msg {
|
||||
&Message::Frame(_) => 0,
|
||||
&Message::Data(_) => 0,
|
||||
&Message::Peers(_) => 1,
|
||||
&Message::GetPeers => 2,
|
||||
&Message::Init(_) => 2,
|
||||
&Message::Close => 3
|
||||
};
|
||||
if options.network_id.is_some() {
|
||||
|
@ -140,7 +161,7 @@ pub fn encode(options: &Options, msg: &Message, buf: &mut [u8]) -> usize {
|
|||
pos += 8;
|
||||
}
|
||||
match msg {
|
||||
&Message::Frame(ref data) => {
|
||||
&Message::Data(ref data) => {
|
||||
assert!(buf.len() >= pos + data.len());
|
||||
unsafe { ptr::copy_nonoverlapping(data.as_ptr(), buf[pos..].as_mut_ptr(), data.len()) };
|
||||
pos += data.len();
|
||||
|
@ -171,7 +192,20 @@ pub fn encode(options: &Options, msg: &Message, buf: &mut [u8]) -> usize {
|
|||
buf[pos] = 0;
|
||||
pos += 1;
|
||||
},
|
||||
&Message::GetPeers => {
|
||||
&Message::Init(ref addrs) => {
|
||||
assert!(buf.len() >= pos + 1);
|
||||
assert!(addrs.len() <= 255);
|
||||
buf[pos] = addrs.len() as u8;
|
||||
pos += 1;
|
||||
for addr in addrs {
|
||||
let bytes = addr.to_bytes();
|
||||
assert!(bytes.len() <= 255);
|
||||
assert!(buf.len() >= pos + 1 + bytes.len());
|
||||
buf[pos] = bytes.len() as u8;
|
||||
pos += 1;
|
||||
unsafe { ptr::copy_nonoverlapping(bytes.as_ptr(), buf[pos..].as_mut_ptr(), bytes.len()) };
|
||||
pos += bytes.len();
|
||||
}
|
||||
},
|
||||
&Message::Close => {
|
||||
}
|
||||
|
@ -184,7 +218,7 @@ pub fn encode(options: &Options, msg: &Message, buf: &mut [u8]) -> usize {
|
|||
fn encode_message_packet() {
|
||||
let options = Options::default();
|
||||
let payload = [1,2,3,4,5];
|
||||
let msg = Message::Frame(&payload);
|
||||
let msg: Message<ethernet::EthAddr> = Message::Data(&payload);
|
||||
let mut buf = [0; 1024];
|
||||
let size = encode(&options, &msg, &mut buf[..]);
|
||||
assert_eq!(size, 13);
|
||||
|
@ -198,7 +232,7 @@ fn encode_message_packet() {
|
|||
fn encode_message_peers() {
|
||||
use std::str::FromStr;
|
||||
let options = Options::default();
|
||||
let msg: Message = Message::Peers(vec![SocketAddr::from_str("1.2.3.4:123").unwrap(), SocketAddr::from_str("5.6.7.8:12345").unwrap()]);
|
||||
let msg: Message<ethernet::EthAddr> = Message::Peers(vec![SocketAddr::from_str("1.2.3.4:123").unwrap(), SocketAddr::from_str("5.6.7.8:12345").unwrap()]);
|
||||
let mut buf = [0; 1024];
|
||||
let size = encode(&options, &msg, &mut buf[..]);
|
||||
assert_eq!(size, 22);
|
||||
|
@ -212,7 +246,7 @@ fn encode_message_peers() {
|
|||
fn encode_option_network_id() {
|
||||
let mut options = Options::default();
|
||||
options.network_id = Some(134);
|
||||
let msg: Message = Message::GetPeers;
|
||||
let msg: Message<ethernet::EthAddr> = Message::Close;
|
||||
let mut buf = [0; 1024];
|
||||
let size = encode(&options, &msg, &mut buf[..]);
|
||||
assert_eq!(size, 16);
|
||||
|
@ -223,13 +257,14 @@ fn encode_option_network_id() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn encode_message_getpeers() {
|
||||
fn encode_message_init() {
|
||||
let options = Options::default();
|
||||
let msg: Message = Message::GetPeers;
|
||||
let addrs = vec![];
|
||||
let msg: Message<ethernet::EthAddr> = Message::Init(addrs);
|
||||
let mut buf = [0; 1024];
|
||||
let size = encode(&options, &msg, &mut buf[..]);
|
||||
assert_eq!(size, 8);
|
||||
assert_eq!(&buf[..size], &[118,112,110,0,0,0,0,2]);
|
||||
assert_eq!(size, 13);
|
||||
assert_eq!(&buf[..size], &[118,112,110,0,0,0,0,2,1,2,3,4,5]);
|
||||
let (options2, msg2) = decode(&buf[..size]).unwrap();
|
||||
assert_eq!(options, options2);
|
||||
assert_eq!(msg, msg2);
|
||||
|
@ -238,7 +273,7 @@ fn encode_message_getpeers() {
|
|||
#[test]
|
||||
fn encode_message_close() {
|
||||
let options = Options::default();
|
||||
let msg: Message = Message::Close;
|
||||
let msg: Message<ethernet::EthAddr> = Message::Close;
|
||||
let mut buf = [0; 1024];
|
||||
let size = encode(&options, &msg, &mut buf[..]);
|
||||
assert_eq!(size, 8);
|
||||
|
|
Loading…
Reference in New Issue