Recieve first call
parent
56add49645
commit
f3b147a6a3
|
@ -262,6 +262,12 @@ version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "leb128"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.112"
|
version = "0.2.112"
|
||||||
|
@ -364,6 +370,8 @@ name = "nemicosm"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"bytes",
|
||||||
|
"leb128",
|
||||||
"native-tls",
|
"native-tls",
|
||||||
"rustls 0.20.2",
|
"rustls 0.20.2",
|
||||||
"trust-dns-resolver",
|
"trust-dns-resolver",
|
||||||
|
|
|
@ -7,6 +7,8 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.52"
|
anyhow = "1.0.52"
|
||||||
|
bytes = "1.1.0"
|
||||||
|
leb128 = "0.2.5"
|
||||||
native-tls = "0.2.8"
|
native-tls = "0.2.8"
|
||||||
rustls = { version = "0.20.2", features = ["dangerous_configuration"] }
|
rustls = { version = "0.20.2", features = ["dangerous_configuration"] }
|
||||||
trust-dns-resolver = { version = "0.20.3", features = ["dns-over-rustls"] }
|
trust-dns-resolver = { version = "0.20.3", features = ["dns-over-rustls"] }
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
trait Object {
|
||||||
|
fn id(&self) -> u64;
|
||||||
|
|
||||||
|
fn interfaces(self) -> Vec<String>;
|
||||||
|
|
||||||
|
fn release(self);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
71
src/main.rs
71
src/main.rs
|
@ -1,10 +1,15 @@
|
||||||
|
// mod leb128;
|
||||||
|
mod num;
|
||||||
|
mod object;
|
||||||
|
mod proto;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
io::{Read, Write},
|
io::{Read, Write},
|
||||||
net::TcpStream,
|
net::TcpStream,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{ensure, Context, Result};
|
||||||
// use native_tls::TlsConnector;
|
// use native_tls::TlsConnector;
|
||||||
// use native_tls::TlsConnector;
|
// use native_tls::TlsConnector;
|
||||||
use rustls::{
|
use rustls::{
|
||||||
|
@ -17,8 +22,12 @@ use trust_dns_resolver::{
|
||||||
};
|
};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use num::Vu64;
|
||||||
|
|
||||||
|
use crate::num::Vu32;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let (port, host) = resolve_dns("daeken.dev")?;
|
// let (port, host) = resolve_dns("daeken.dev")?;
|
||||||
let port = 12345;
|
let port = 12345;
|
||||||
let host = "localhost";
|
let host = "localhost";
|
||||||
|
|
||||||
|
@ -29,25 +38,61 @@ fn main() -> Result<()> {
|
||||||
let mut tls_conn = make_tls_connection(tls_conf, &host, port)
|
let mut tls_conn = make_tls_connection(tls_conf, &host, port)
|
||||||
.with_context(|| format!("Can't connect to {}:{}", host, port))?;
|
.with_context(|| format!("Can't connect to {}:{}", host, port))?;
|
||||||
|
|
||||||
let uuid = Uuid::new_v4();
|
let mut uuid = Uuid::new_v4().as_u128().to_le_bytes();
|
||||||
dbg!(&uuid);
|
uuid[0] = 0;
|
||||||
tls_conn
|
uuid[1] = 0;
|
||||||
.write_all(uuid.as_bytes())
|
uuid[2] = 0;
|
||||||
.context("Can't write UUID")?;
|
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];
|
let mut serv_uuid = [0; 16];
|
||||||
tls_conn.read_exact(&mut serv_uuid)?;
|
tls_conn.read_exact(&mut serv_uuid)?;
|
||||||
let serv_uuid = Uuid::from_bytes(serv_uuid);
|
let serv_uuid = Uuid::from_bytes(serv_uuid);
|
||||||
|
|
||||||
|
ensure!(serv_uuid != uuid);
|
||||||
|
|
||||||
dbg!(serv_uuid);
|
dbg!(serv_uuid);
|
||||||
|
|
||||||
// Hangs ATM
|
let mut command_no = 0;
|
||||||
let mut new = [0; 100];
|
let mut recv_buff = Vec::new();
|
||||||
tls_conn.write_all(&new)?;
|
|
||||||
let len = tls_conn.read(&mut 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?
|
// TODO: How to cache this?
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
struct Object {
|
||||||
|
handler: Handler,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Handler = fn(u32, &[u32]);
|
|
@ -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,
|
||||||
|
}
|
Loading…
Reference in New Issue