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"
|
||||
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",
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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::{
|
||||
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?
|
||||
|
|
|
@ -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