mirror of https://github.com/dswd/vpncloud.git
First cloud test
This commit is contained in:
parent
452a022bc3
commit
c750947ab0
53
src/cloud.rs
53
src/cloud.rs
|
@ -201,7 +201,7 @@ pub struct ReconnectEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct GenericCloud<P: Protocol, T: Table, S: Socket, TS: TimeSource> {
|
pub struct GenericCloud<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> {
|
||||||
config: Config,
|
config: Config,
|
||||||
magic: HeaderMagic,
|
magic: HeaderMagic,
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
|
@ -214,7 +214,7 @@ pub struct GenericCloud<P: Protocol, T: Table, S: Socket, TS: TimeSource> {
|
||||||
table: T,
|
table: T,
|
||||||
socket4: S,
|
socket4: S,
|
||||||
socket6: S,
|
socket6: S,
|
||||||
device: Device,
|
device: D,
|
||||||
crypto: Crypto,
|
crypto: Crypto,
|
||||||
next_peerlist: Time,
|
next_peerlist: Time,
|
||||||
update_freq: Duration,
|
update_freq: Duration,
|
||||||
|
@ -229,8 +229,8 @@ pub struct GenericCloud<P: Protocol, T: Table, S: Socket, TS: TimeSource> {
|
||||||
_dummy_ts: PhantomData<TS>
|
_dummy_ts: PhantomData<TS>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<P, T, S, TS> {
|
impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D, P, T, S, TS> {
|
||||||
pub fn new(config: &Config, device: Device, table: T,
|
pub fn new(config: &Config, device: D, table: T,
|
||||||
learning: bool, broadcast: bool, addresses: Vec<Range>,
|
learning: bool, broadcast: bool, addresses: Vec<Range>,
|
||||||
crypto: Crypto, port_forwarding: Option<PortForwarding>
|
crypto: Crypto, port_forwarding: Option<PortForwarding>
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -712,6 +712,10 @@ impl<P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<P, T, S, TS>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn decode_message<'a>(&self, msg: &'a mut [u8]) -> Result<Message<'a>, Error> {
|
||||||
|
decode(msg, self.magic, &self.crypto)
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_socket_data(&mut self, src: SocketAddr, data: &mut [u8]) {
|
fn handle_socket_data(&mut self, src: SocketAddr, data: &mut [u8]) {
|
||||||
let size = data.len();
|
let size = data.len();
|
||||||
if let Err(e) = decode(data, self.magic, &mut self.crypto).and_then(|msg| {
|
if let Err(e) = decode(data, self.magic, &mut self.crypto).and_then(|msg| {
|
||||||
|
@ -782,3 +786,44 @@ impl<P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<P, T, S, TS>
|
||||||
self.broadcast_msg(&mut Message::Close).ok();
|
self.broadcast_msg(&mut Message::Close).ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)] use super::ethernet::{self, SwitchTable};
|
||||||
|
#[cfg(test)] use super::util::MockTimeSource;
|
||||||
|
#[cfg(test)] use super::net::MockSocket;
|
||||||
|
#[cfg(test)] use super::device::MockDevice;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl<P: Protocol, T: Table, TS: TimeSource> GenericCloud<MockDevice, P, T, MockSocket, TS> {
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.device.is_empty() && self.socket4.is_empty() && self.socket6.is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
type TestNode = GenericCloud<MockDevice, ethernet::Frame, SwitchTable<MockTimeSource>, MockSocket, MockTimeSource>;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn create_node() -> TestNode {
|
||||||
|
TestNode::new(
|
||||||
|
&Config::default(),
|
||||||
|
MockDevice::new(),
|
||||||
|
SwitchTable::new(1800, 10),
|
||||||
|
true, true, vec![], Crypto::None, None
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn connect() {
|
||||||
|
let mut node = create_node();
|
||||||
|
assert!(node.is_empty());
|
||||||
|
node.connect("1.2.3.4:5678").unwrap();
|
||||||
|
assert!(node.device.is_empty());
|
||||||
|
assert!(node.socket6.is_empty());
|
||||||
|
let (addr, mut message) = node.socket4.pop_outbound().unwrap();
|
||||||
|
assert_eq!("1.2.3.4:5678".to_socket_addrs().unwrap().next().unwrap(), addr);
|
||||||
|
let message = node.decode_message(&mut message).unwrap();
|
||||||
|
assert_eq!(Message::Init(0, node.node_id, vec![]), message);
|
||||||
|
|
||||||
|
}
|
175
src/device.rs
175
src/device.rs
|
@ -3,9 +3,10 @@
|
||||||
// This software is licensed under GPL-3 or newer (see LICENSE.md)
|
// This software is licensed under GPL-3 or newer (see LICENSE.md)
|
||||||
|
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
use std::io::{self, Error as IoError, Read, Write};
|
use std::io::{self, Error as IoError, ErrorKind, Read, Write};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use super::types::Error;
|
use super::types::Error;
|
||||||
|
|
||||||
|
@ -40,15 +41,48 @@ impl fmt::Display for Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub trait Device: AsRawFd {
|
||||||
|
/// Returns the type of this device
|
||||||
|
fn get_type(&self) -> Type;
|
||||||
|
|
||||||
|
/// Returns the interface name of this device.
|
||||||
|
fn ifname(&self) -> &str;
|
||||||
|
|
||||||
|
/// Reads a packet/frame from the device
|
||||||
|
///
|
||||||
|
/// This method reads one packet or frame (depending on the device type) into the `buffer`.
|
||||||
|
/// The `buffer` must be large enough to hold a packet/frame of maximum size, otherwise the
|
||||||
|
/// packet/frame will be split.
|
||||||
|
/// The method will block until a packet/frame is ready to be read.
|
||||||
|
/// On success, the method will return the starting position and the amount of bytes read into
|
||||||
|
/// the buffer.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// This method will return an error if the underlying read call fails.
|
||||||
|
fn read(&mut self, buffer: &mut [u8]) -> Result<(usize, usize), Error>;
|
||||||
|
|
||||||
|
/// Writes a packet/frame to the device
|
||||||
|
///
|
||||||
|
/// This method writes one packet or frame (depending on the device type) from `data` to the
|
||||||
|
/// device. The data starts at the position `start` in the buffer. The buffer should have at
|
||||||
|
/// least 4 bytes of space before the start of the packet.
|
||||||
|
/// The method will block until the packet/frame has been written.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// This method will return an error if the underlying read call fails.
|
||||||
|
fn write(&mut self, data: &mut [u8], start: usize) -> Result<(), Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Represents a tun/tap device
|
/// Represents a tun/tap device
|
||||||
pub struct Device {
|
pub struct TunTapDevice {
|
||||||
fd: fs::File,
|
fd: fs::File,
|
||||||
ifname: String,
|
ifname: String,
|
||||||
type_: Type,
|
type_: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Device {
|
impl TunTapDevice {
|
||||||
/// Creates a new tun/tap device
|
/// Creates a new tun/tap device
|
||||||
///
|
///
|
||||||
/// This method creates a new device of the `type_` kind with the name `ifname`.
|
/// This method creates a new device of the `type_` kind with the name `ifname`.
|
||||||
|
@ -91,7 +125,7 @@ impl Device {
|
||||||
while ifname_c.last() == Some(&0) {
|
while ifname_c.last() == Some(&0) {
|
||||||
ifname_c.pop();
|
ifname_c.pop();
|
||||||
}
|
}
|
||||||
Ok(Device{fd, ifname: String::from_utf8(ifname_c).unwrap(), type_})
|
Ok(Self{fd, ifname: String::from_utf8(ifname_c).unwrap(), type_})
|
||||||
},
|
},
|
||||||
_ => Err(IoError::last_os_error())
|
_ => Err(IoError::last_os_error())
|
||||||
}
|
}
|
||||||
|
@ -106,19 +140,6 @@ impl Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the interface name of this device.
|
|
||||||
#[inline]
|
|
||||||
pub fn ifname(&self) -> &str {
|
|
||||||
&self.ifname
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the type of this device
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
pub fn get_type(&self) -> Type {
|
|
||||||
self.type_
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a dummy device based on an existing file
|
/// Creates a dummy device based on an existing file
|
||||||
///
|
///
|
||||||
/// This method opens a regular or special file and reads from it to receive packets and
|
/// This method opens a regular or special file and reads from it to receive packets and
|
||||||
|
@ -134,31 +155,13 @@ impl Device {
|
||||||
/// This method will return an error if the file can not be opened for reading and writing.
|
/// This method will return an error if the file can not be opened for reading and writing.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn dummy(ifname: &str, path: &str, type_: Type) -> io::Result<Self> {
|
pub fn dummy(ifname: &str, path: &str, type_: Type) -> io::Result<Self> {
|
||||||
Ok(Device{
|
Ok(TunTapDevice{
|
||||||
fd: try!(fs::OpenOptions::new().create(true).read(true).write(true).open(path)),
|
fd: try!(fs::OpenOptions::new().create(true).read(true).write(true).open(path)),
|
||||||
ifname: ifname.to_string(),
|
ifname: ifname.to_string(),
|
||||||
type_
|
type_
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads a packet/frame from the device
|
|
||||||
///
|
|
||||||
/// This method reads one packet or frame (depending on the device type) into the `buffer`.
|
|
||||||
/// The `buffer` must be large enough to hold a packet/frame of maximum size, otherwise the
|
|
||||||
/// packet/frame will be split.
|
|
||||||
/// The method will block until a packet/frame is ready to be read.
|
|
||||||
/// On success, the method will return the starting position and the amount of bytes read into
|
|
||||||
/// the buffer.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
/// This method will return an error if the underlying read call fails.
|
|
||||||
#[inline]
|
|
||||||
pub fn read(&mut self, mut buffer: &mut [u8]) -> Result<(usize, usize), Error> {
|
|
||||||
let read = try!(self.fd.read(&mut buffer).map_err(|e| Error::TunTapDev("Read error", e)));
|
|
||||||
let (start, read) = self.correct_data_after_read(&mut buffer, 0, read);
|
|
||||||
Ok((start, read))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn correct_data_after_read(&mut self, _buffer: &mut [u8], start: usize, read: usize) -> (usize, usize) {
|
fn correct_data_after_read(&mut self, _buffer: &mut [u8], start: usize, read: usize) -> (usize, usize) {
|
||||||
|
@ -179,24 +182,6 @@ impl Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes a packet/frame to the device
|
|
||||||
///
|
|
||||||
/// This method writes one packet or frame (depending on the device type) from `data` to the
|
|
||||||
/// device. The data starts at the position `start` in the buffer. The buffer should have at
|
|
||||||
/// least 4 bytes of space before the start of the packet.
|
|
||||||
/// The method will block until the packet/frame has been written.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
/// This method will return an error if the underlying read call fails.
|
|
||||||
#[inline]
|
|
||||||
pub fn write(&mut self, mut data: &mut [u8], start: usize) -> Result<(), Error> {
|
|
||||||
let start = self.correct_data_before_write(&mut data, start);
|
|
||||||
match self.fd.write_all(&data[start..]) {
|
|
||||||
Ok(_) => self.fd.flush().map_err(|e| Error::TunTapDev("Flush error", e)),
|
|
||||||
Err(e) => Err(Error::TunTapDev("Write error", e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn correct_data_before_write(&mut self, _buffer: &mut [u8], start: usize) -> usize {
|
fn correct_data_before_write(&mut self, _buffer: &mut [u8], start: usize) -> usize {
|
||||||
|
@ -223,9 +208,89 @@ impl Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRawFd for Device {
|
impl Device for TunTapDevice {
|
||||||
|
fn get_type(&self) -> Type {
|
||||||
|
self.type_
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ifname(&self) -> &str {
|
||||||
|
&self.ifname
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(&mut self, mut buffer: &mut [u8]) -> Result<(usize, usize), Error> {
|
||||||
|
let read = try!(self.fd.read(&mut buffer).map_err(|e| Error::TunTapDev("Read error", e)));
|
||||||
|
let (start, read) = self.correct_data_after_read(&mut buffer, 0, read);
|
||||||
|
Ok((start, read))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, mut data: &mut [u8], start: usize) -> Result<(), Error> {
|
||||||
|
let start = self.correct_data_before_write(&mut data, start);
|
||||||
|
match self.fd.write_all(&data[start..]) {
|
||||||
|
Ok(_) => self.fd.flush().map_err(|e| Error::TunTapDev("Flush error", e)),
|
||||||
|
Err(e) => Err(Error::TunTapDev("Write error", e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRawFd for TunTapDevice {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
self.fd.as_raw_fd()
|
self.fd.as_raw_fd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct MockDevice {
|
||||||
|
inbound: VecDeque<Vec<u8>>,
|
||||||
|
outbound: VecDeque<Vec<u8>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MockDevice {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { outbound: VecDeque::new(), inbound: VecDeque::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn put_inbound(&mut self, data: Vec<u8>) {
|
||||||
|
self.inbound.push_back(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_outbound(&mut self) -> Option<Vec<u8>> {
|
||||||
|
self.outbound.pop_front()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.inbound.is_empty() && self.outbound.is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device for MockDevice {
|
||||||
|
fn get_type(&self) -> Type {
|
||||||
|
Type::Dummy
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ifname(&self) -> &str {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(&mut self, buffer: &mut [u8]) -> Result<(usize, usize), Error> {
|
||||||
|
if let Some(data) = self.inbound.pop_front() {
|
||||||
|
buffer[0..data.len()].copy_from_slice(&data);
|
||||||
|
Ok((0, data.len()))
|
||||||
|
} else {
|
||||||
|
Err(Error::TunTapDev("empty", io::Error::from(ErrorKind::UnexpectedEof)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, data: &mut [u8], start: usize) -> Result<(), Error> {
|
||||||
|
self.outbound.push_back(data[start..].to_owned());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRawFd for MockDevice {
|
||||||
|
#[inline]
|
||||||
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
14
src/main.rs
14
src/main.rs
|
@ -50,7 +50,7 @@ use std::path::Path;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::net::UdpSocket;
|
use std::net::UdpSocket;
|
||||||
|
|
||||||
use device::{Device, Type};
|
use device::{TunTapDevice, Device, Type};
|
||||||
use ethernet::SwitchTable;
|
use ethernet::SwitchTable;
|
||||||
use ip::RoutingTable;
|
use ip::RoutingTable;
|
||||||
use types::{Mode, Range, Protocol, HeaderMagic, Error};
|
use types::{Mode, Range, Protocol, HeaderMagic, Error};
|
||||||
|
@ -161,20 +161,20 @@ enum AnyTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AnyCloud<P: Protocol> {
|
enum AnyCloud<P: Protocol> {
|
||||||
Switch(GenericCloud<P, SwitchTable<SystemTimeSource>, UdpSocket, SystemTimeSource>),
|
Switch(GenericCloud<TunTapDevice, P, SwitchTable<SystemTimeSource>, UdpSocket, SystemTimeSource>),
|
||||||
Routing(GenericCloud<P, RoutingTable, UdpSocket, SystemTimeSource>)
|
Routing(GenericCloud<TunTapDevice, P, RoutingTable, UdpSocket, SystemTimeSource>)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Protocol> AnyCloud<P> {
|
impl<P: Protocol> AnyCloud<P> {
|
||||||
#[allow(unknown_lints, clippy::too_many_arguments)]
|
#[allow(unknown_lints, clippy::too_many_arguments)]
|
||||||
fn new(config: &Config, device: Device, table: AnyTable,
|
fn new(config: &Config, device: TunTapDevice, table: AnyTable,
|
||||||
learning: bool, broadcast: bool, addresses: Vec<Range>,
|
learning: bool, broadcast: bool, addresses: Vec<Range>,
|
||||||
crypto: Crypto, port_forwarding: Option<PortForwarding>) -> Self {
|
crypto: Crypto, port_forwarding: Option<PortForwarding>) -> Self {
|
||||||
match table {
|
match table {
|
||||||
AnyTable::Switch(t) => AnyCloud::Switch(GenericCloud::<P, SwitchTable<SystemTimeSource>, UdpSocket, SystemTimeSource>::new(
|
AnyTable::Switch(t) => AnyCloud::Switch(GenericCloud::<TunTapDevice, P, SwitchTable<SystemTimeSource>, UdpSocket, SystemTimeSource>::new(
|
||||||
config, device,t, learning, broadcast, addresses, crypto, port_forwarding
|
config, device,t, learning, broadcast, addresses, crypto, port_forwarding
|
||||||
)),
|
)),
|
||||||
AnyTable::Routing(t) => AnyCloud::Routing(GenericCloud::<P, RoutingTable, UdpSocket, SystemTimeSource>::new(
|
AnyTable::Routing(t) => AnyCloud::Routing(GenericCloud::<TunTapDevice, P, RoutingTable, UdpSocket, SystemTimeSource>::new(
|
||||||
config, device,t, learning, broadcast, addresses, crypto, port_forwarding
|
config, device,t, learning, broadcast, addresses, crypto, port_forwarding
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ impl<P: Protocol> AnyCloud<P> {
|
||||||
|
|
||||||
|
|
||||||
fn run<P: Protocol> (config: Config) {
|
fn run<P: Protocol> (config: Config) {
|
||||||
let device = try_fail!(Device::new(&config.device_name, config.device_type, config.device_path.as_ref().map(|s| s as &str)),
|
let device = try_fail!(TunTapDevice::new(&config.device_name, config.device_type, config.device_path.as_ref().map(|s| s as &str)),
|
||||||
"Failed to open virtual {} interface {}: {}", config.device_type, config.device_name);
|
"Failed to open virtual {} interface {}: {}", config.device_type, config.device_name);
|
||||||
info!("Opened device {}", device.ifname());
|
info!("Opened device {}", device.ifname());
|
||||||
let mut ranges = Vec::with_capacity(config.subnets.len());
|
let mut ranges = Vec::with_capacity(config.subnets.len());
|
||||||
|
|
|
@ -54,6 +54,10 @@ impl MockSocket {
|
||||||
pub fn pop_outbound(&mut self) -> Option<(SocketAddr, Vec<u8>)> {
|
pub fn pop_outbound(&mut self) -> Option<(SocketAddr, Vec<u8>)> {
|
||||||
self.outbound.pop_front()
|
self.outbound.pop_front()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.inbound.is_empty() && self.outbound.is_empty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRawFd for MockSocket {
|
impl AsRawFd for MockSocket {
|
||||||
|
|
|
@ -7,7 +7,6 @@ use libc;
|
||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::RawFd;
|
||||||
use std::io;
|
use std::io;
|
||||||
use device::Device;
|
use device::Device;
|
||||||
use std::os::unix::io::AsRawFd;
|
|
||||||
|
|
||||||
use super::WaitResult;
|
use super::WaitResult;
|
||||||
use ::device::Type;
|
use ::device::Type;
|
||||||
|
|
|
@ -78,7 +78,7 @@ impl<'a> fmt::Debug for Message<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unknown_lints,clippy::needless_range_loop)]
|
#[allow(unknown_lints,clippy::needless_range_loop)]
|
||||||
pub fn decode<'a>(data: &'a mut [u8], magic: HeaderMagic, crypto: &mut Crypto) -> Result<Message<'a>, Error> {
|
pub fn decode<'a>(data: &'a mut [u8], magic: HeaderMagic, crypto: &Crypto) -> Result<Message<'a>, Error> {
|
||||||
let mut end = data.len();
|
let mut end = data.len();
|
||||||
let (header, mut pos) = try!(TopHeader::read_from(&data[..end]));
|
let (header, mut pos) = try!(TopHeader::read_from(&data[..end]));
|
||||||
if header.magic != magic {
|
if header.magic != magic {
|
||||||
|
|
Loading…
Reference in New Issue