Recieve first call

trunk
Alona EM 2022-01-15 01:13:46 +00:00
parent 56add49645
commit f3b147a6a3
8 changed files with 427 additions and 13 deletions

8
Cargo.lock generated
View File

@ -262,6 +262,12 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "leb128"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
[[package]]
name = "libc"
version = "0.2.112"
@ -364,6 +370,8 @@ name = "nemicosm"
version = "0.1.0"
dependencies = [
"anyhow",
"bytes",
"leb128",
"native-tls",
"rustls 0.20.2",
"trust-dns-resolver",

View File

@ -7,6 +7,8 @@ edition = "2021"
[dependencies]
anyhow = "1.0.52"
bytes = "1.1.0"
leb128 = "0.2.5"
native-tls = "0.2.8"
rustls = { version = "0.20.2", features = ["dangerous_configuration"] }
trust-dns-resolver = { version = "0.20.3", features = ["dns-over-rustls"] }

7
src/gen.rs Normal file
View File

@ -0,0 +1,7 @@
trait Object {
fn id(&self) -> u64;
fn interfaces(self) -> Vec<String>;
fn release(self);
}

234
src/leb128.rs Normal file
View File

@ -0,0 +1,234 @@
/*
Taken from the `leb128` crate, which is Apache2 / MIT dual licensed
Copyright (c) 2015 The Rust Project Developers
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
/*
We have our own version because it's important to know how many bytes were read;
TODO: If somehow this is hot, theirs a branchless SIMD version, I read about on
wikipedia
*/
pub const CONTINUATION_BIT: u8 = 1 << 7;
pub const SIGN_BIT: u8 = 1 << 6;
pub fn low_bits_of_byte(byte: u8) -> u8 {
byte & !CONTINUATION_BIT
}
pub fn low_bits_of_u64(val: u64) -> u8 {
let byte = val & (std::u8::MAX as u64);
low_bits_of_byte(byte as u8)
}
/// A module for reading LEB128-encoded signed and unsigned integers.
pub mod read {
use super::{low_bits_of_byte, CONTINUATION_BIT, SIGN_BIT};
use std::fmt;
use std::io;
/// An error type for reading LEB128-encoded values.
#[derive(Debug)]
pub enum Error {
/// There was an underlying IO error.
IoError(io::Error),
/// The number being read is larger than can be represented.
Overflow,
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
Error::IoError(e)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Error::IoError(ref e) => e.fmt(f),
Error::Overflow => {
write!(f, "The number being read is larger than can be represented")
}
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self {
Error::IoError(ref e) => Some(e),
Error::Overflow => None,
}
}
}
/// Read an unsigned LEB128-encoded number from the `std::io::Read` stream
/// `r`.
///
/// On success, return the number, and the number of bytes read.
pub fn unsigned<R>(r: &mut R) -> Result<(u64, usize), Error>
where
R: ?Sized + io::Read,
{
let mut result = 0;
let mut shift = 0;
let mut read = 0;
loop {
let mut buf = [0];
r.read_exact(&mut buf)?;
read += 1;
if shift == 63 && buf[0] != 0x00 && buf[0] != 0x01 {
while buf[0] & CONTINUATION_BIT != 0 {
r.read_exact(&mut buf)?;
read += 1;
}
return Err(Error::Overflow);
}
let low_bits = low_bits_of_byte(buf[0]) as u64;
result |= low_bits << shift;
if buf[0] & CONTINUATION_BIT == 0 {
return Ok((result, read));
}
shift += 7;
}
}
/// Read a signed LEB128-encoded number from the `std::io::Read` stream `r`.
///
/// On success, return the number and the number of bytes read.
pub fn signed<R>(r: &mut R) -> Result<(i64, usize), Error>
where
R: ?Sized + io::Read,
{
let mut result = 0;
let mut shift = 0;
let size = 64;
let mut byte;
let mut read = 0;
loop {
let mut buf = [0];
r.read_exact(&mut buf)?;
read += 1;
byte = buf[0];
if shift == 63 && byte != 0x00 && byte != 0x7f {
while buf[0] & CONTINUATION_BIT != 0 {
r.read_exact(&mut buf)?;
read += 1;
}
return Err(Error::Overflow);
}
let low_bits = low_bits_of_byte(byte) as i64;
result |= low_bits << shift;
shift += 7;
if byte & CONTINUATION_BIT == 0 {
break;
}
}
if shift < size && (SIGN_BIT & byte) == SIGN_BIT {
// Sign extend the result.
result |= !0 << shift;
}
Ok((result, read))
}
}
/// A module for writing LEB128-encoded signed and unsigned integers.
pub mod write {
use super::{low_bits_of_u64, CONTINUATION_BIT};
use std::io;
/// Write `val` to the `std::io::Write` stream `w` as an unsigned LEB128 value.
///
/// On success, return the number of bytes written to `w`.
pub fn unsigned<W>(w: &mut W, mut val: u64) -> Result<usize, io::Error>
where
W: ?Sized + io::Write,
{
let mut bytes_written = 0;
loop {
let mut byte = low_bits_of_u64(val);
val >>= 7;
if val != 0 {
// More bytes to come, so set the continuation bit.
byte |= CONTINUATION_BIT;
}
let buf = [byte];
w.write_all(&buf)?;
bytes_written += 1;
if val == 0 {
return Ok(bytes_written);
}
}
}
/// Write `val` to the `std::io::Write` stream `w` as a signed LEB128 value.
///
/// On success, return the number of bytes written to `w`.
pub fn signed<W>(w: &mut W, mut val: i64) -> Result<usize, io::Error>
where
W: ?Sized + io::Write,
{
let mut bytes_written = 0;
loop {
let mut byte = val as u8;
// Keep the sign bit for testing
val >>= 6;
let done = val == 0 || val == -1;
if done {
byte &= !CONTINUATION_BIT;
} else {
// Remove the sign bit
val >>= 1;
// More bytes to come, so set the continuation bit.
byte |= CONTINUATION_BIT;
}
let buf = [byte];
w.write_all(&buf)?;
bytes_written += 1;
if done {
return Ok(bytes_written);
}
}
}
}

View File

@ -1,10 +1,15 @@
// mod leb128;
mod num;
mod object;
mod proto;
use std::{
io::{Read, Write},
net::TcpStream,
sync::Arc,
};
use anyhow::{Context, Result};
use anyhow::{ensure, Context, Result};
// use native_tls::TlsConnector;
// use native_tls::TlsConnector;
use rustls::{
@ -17,8 +22,12 @@ use trust_dns_resolver::{
};
use uuid::Uuid;
use num::Vu64;
use crate::num::Vu32;
fn main() -> Result<()> {
let (port, host) = resolve_dns("daeken.dev")?;
// let (port, host) = resolve_dns("daeken.dev")?;
let port = 12345;
let host = "localhost";
@ -29,25 +38,61 @@ fn main() -> Result<()> {
let mut tls_conn = make_tls_connection(tls_conf, &host, port)
.with_context(|| format!("Can't connect to {}:{}", host, port))?;
let uuid = Uuid::new_v4();
dbg!(&uuid);
tls_conn
.write_all(uuid.as_bytes())
.context("Can't write UUID")?;
let mut uuid = Uuid::new_v4().as_u128().to_le_bytes();
uuid[0] = 0;
uuid[1] = 0;
uuid[2] = 0;
uuid[3] = 0;
tls_conn.write_all(&uuid).context("Can't write UUID")?;
let uuid = Uuid::from_bytes(uuid);
dbg!(uuid);
let mut serv_uuid = [0; 16];
tls_conn.read_exact(&mut serv_uuid)?;
let serv_uuid = Uuid::from_bytes(serv_uuid);
ensure!(serv_uuid != uuid);
dbg!(serv_uuid);
// Hangs ATM
let mut new = [0; 100];
tls_conn.write_all(&new)?;
let len = tls_conn.read(&mut new)?;
let mut command_no = 0;
let mut recv_buff = Vec::new();
dbg!(&new[..len]);
loop {
// Recieve step
let mut compression = [0];
let l = tls_conn.read(&mut compression)?;
match l {
0 => {}
1 => {
assert_eq!(compression, [0]);
Ok(())
// Handle recieve
let len = Vu64::read(&mut tls_conn)?;
dbg!(len);
recv_buff.resize(len.0 as usize, 0);
tls_conn.read_exact(&mut recv_buff)?;
dbg!(&recv_buff);
let mut recv_buff = &recv_buff[..];
let seq_num = Vu64::read(&mut recv_buff)?;
if (seq_num & 1) == 0 {
// LSB = 0: This is a call, we need to respond
dbg!(seq_num);
let command_no = Vu32::read(&mut recv_buff)?;
let obj_id = Vu64::read(&mut recv_buff)?;
let serialised = recv_buff;
dbg!(command_no, obj_id, serialised);
} else {
// This is a reponce to something we've asked for
}
}
_ => unreachable!("Should only have read one byte"),
}
}
}
// TODO: How to cache this?

72
src/num.rs Normal file
View File

@ -0,0 +1,72 @@
use std::{
io::{self, Read, Write},
num::TryFromIntError,
ops::BitAnd,
};
#[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) struct Vu64(pub(crate) u64);
impl Vu64 {
pub(crate) fn read<R: Read + ?Sized>(r: &mut R) -> io::Result<Self> {
leb128::read::unsigned(r).map_err(leb_err).map(Self)
}
pub(crate) fn write<W: Write + ?Sized>(&self, w: &mut W) -> io::Result<usize> {
leb128::write::unsigned(w, self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) struct Vu32(pub(crate) u32);
impl Vu32 {
pub(crate) fn read<R: Read + ?Sized>(r: &mut R) -> io::Result<Self> {
leb128::read::unsigned(r)
.map_err(leb_err)?
.try_into()
.map(Self)
.map_err(conv_err)
}
pub(crate) fn write<W: Write + ?Sized>(&self, w: &mut W) -> io::Result<usize> {
leb128::write::unsigned(w, self.0.into())
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) struct Vi32(pub(crate) i32);
impl Vi32 {
pub(crate) fn read<R: Read + ?Sized>(r: &mut R) -> io::Result<Self> {
leb128::read::signed(r)
.map_err(leb_err)?
.try_into()
.map(Self)
.map_err(conv_err)
}
pub(crate) fn write<W: Write + ?Sized>(&self, w: &mut W) -> io::Result<usize> {
leb128::write::signed(w, self.0.into())
}
}
fn conv_err(e: TryFromIntError) -> io::Error {
io::Error::new(io::ErrorKind::InvalidData, e)
}
fn leb_err(e: leb128::read::Error) -> io::Error {
match e {
leb128::read::Error::IoError(e) => e,
leb128::read::Error::Overflow => io::Error::new(io::ErrorKind::InvalidData, e),
}
}
impl BitAnd<u64> for Vu64 {
type Output = u64;
fn bitand(self, rhs: u64) -> Self::Output {
self.0 & rhs
}
}

5
src/object.rs Normal file
View File

@ -0,0 +1,5 @@
struct Object {
handler: Handler,
}
type Handler = fn(u32, &[u32]);

41
src/proto.rs Normal file
View File

@ -0,0 +1,41 @@
use bytes::Bytes;
use crate::num::{Vi32, Vu64};
type ObjId = Vu64;
struct Header {
compression: Compression,
wire_lenght: Vu64,
}
struct Call {
header: Header,
/// Identifies what call/responce this is part of
///
/// LSB always 0
sequence: Vu64,
/// What function to execute
command_number: Vi32,
/// What object to execute it on
object: ObjId,
/// Serialized arguments to the function
data: Bytes,
}
struct Responce {
header: Header,
/// Identifies what call/responce this is part of
///
/// LSB always 1
sequence: Vu64,
/// Result of the call
status: Vi32,
/// Serialized result of the call
data: Bytes,
}
#[repr(u8)]
enum Compression {
None = 0,
}