initial modem commit

This commit is contained in:
Daniella / Tove 2023-10-01 16:45:40 +02:00
parent 3181706ef3
commit 9b5c37ceb3
Signed by: TudbuT
GPG key ID: 7D63D5634B7C417F
9 changed files with 344 additions and 55 deletions

97
Cargo.lock generated
View file

@ -10,23 +10,37 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "enum-ordinalize"
version = "3.1.12"
version = "3.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a62bb1df8b45ecb7ffa78dca1c17a438fb193eb083db0b1b494d2a61bcb5096a"
checksum = "1bf1fa3f06bbff1ea5b1a9c7b14aa992a39657db60a2759457328d7e058f49ee"
dependencies = [
"num-bigint",
"num-traits",
"proc-macro2",
"quote",
"rustc_version",
"syn",
]
[[package]]
name = "num-bigint"
version = "0.4.3"
name = "ioctl-rs"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
checksum = "f7970510895cee30b3e9128319f2cefd4bde883a39f38baa279567ba3a7eb97d"
dependencies = [
"libc",
]
[[package]]
name = "libc"
version = "0.2.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
[[package]]
name = "num-bigint"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
dependencies = [
"autocfg",
"num-integer",
@ -45,27 +59,27 @@ dependencies = [
[[package]]
name = "num-traits"
version = "0.2.15"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
dependencies = [
"autocfg",
]
[[package]]
name = "proc-macro2"
version = "1.0.50"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2"
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.23"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
@ -75,28 +89,56 @@ name = "revpfw3"
version = "0.3.1"
dependencies = [
"enum-ordinalize",
"serial",
]
[[package]]
name = "rustc_version"
name = "serial"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
checksum = "a1237a96570fc377c13baa1b88c7589ab66edced652e43ffb17088f003db3e86"
dependencies = [
"semver",
"serial-core",
"serial-unix",
"serial-windows",
]
[[package]]
name = "semver"
version = "1.0.16"
name = "serial-core"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
checksum = "3f46209b345401737ae2125fe5b19a77acce90cd53e1658cda928e4fe9a64581"
dependencies = [
"libc",
]
[[package]]
name = "serial-unix"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f03fbca4c9d866e24a459cbca71283f545a37f8e3e002ad8c70593871453cab7"
dependencies = [
"ioctl-rs",
"libc",
"serial-core",
"termios",
]
[[package]]
name = "serial-windows"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15c6d3b776267a75d31bbdfd5d36c0ca051251caafc285827052bc53bcdc8162"
dependencies = [
"libc",
"serial-core",
]
[[package]]
name = "syn"
version = "1.0.107"
version = "2.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
dependencies = [
"proc-macro2",
"quote",
@ -104,7 +146,16 @@ dependencies = [
]
[[package]]
name = "unicode-ident"
version = "1.0.6"
name = "termios"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
checksum = "d5d9cf598a6d7ce700a4e6a9199da127e6819a61e64b68609683cc9a01b5683a"
dependencies = [
"libc",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"

View file

@ -10,3 +10,4 @@ edition = "2021"
[dependencies]
enum-ordinalize = "3.1"
serial = "0.4"

28
modem-init.txt Normal file
View file

@ -0,0 +1,28 @@
AT
AT+CFUN?
AT+CPIN?
AT+CIPMODE=1
AT+CSTT="internet.telekom","",""
AT+CIICR
AT+CIFSR
AT+CIPSTART=TCP,"$IP",$PORT

View file

@ -1,27 +1,89 @@
use std::{
collections::HashMap,
io::Read,
io::Write,
io::{Read, Write},
net::{Shutdown, TcpStream},
thread,
time::{Duration, SystemTime},
vec,
};
use crate::{io_sync, PacketType, SocketAdapter};
use serial::SerialPort;
pub fn client(ip: &str, port: u16, dest_ip: &str, dest_port: u16, key: &str, sleep_delay_ms: u64) {
use crate::{io_sync, Connection, PacketType, SocketAdapter};
pub struct ClientParams<'a> {
pub server_ip: &'a str,
pub server_port: u16,
pub dest_ip: &'a str,
pub dest_port: u16,
pub key: &'a str,
pub sleep_delay_ms: u64,
pub modem_port: Option<&'a str>,
pub modem_baud: Option<u32>,
pub modem_init: Option<&'a str>,
}
fn connect(params: &ClientParams) -> Connection {
if let Some(modem_port) = params.modem_port {
let mut serial = serial::open(modem_port).unwrap();
serial
.configure(&serial::PortSettings {
baud_rate: serial::BaudRate::from_speed(
params.modem_baud.unwrap_or(115200) as usize
),
char_size: serial::CharSize::Bits8,
parity: serial::Parity::ParityNone,
stop_bits: serial::StopBits::Stop1,
flow_control: serial::FlowControl::FlowNone,
})
.unwrap();
if let Some(modem_init) = params.modem_init {
serial.set_timeout(Duration::from_millis(200)).unwrap();
for line in modem_init.lines() {
let line = line
.replace("$IP", &params.server_ip.to_string())
.replace("$PORT", &params.server_port.to_string());
println!("> {line}");
serial.write_all((line + "\r\n").as_bytes()).unwrap();
let mut s = Vec::new();
let _ = serial.read_to_end(&mut s).is_ok();
if !s.is_empty() {
println!(
"< {}",
String::from_utf8(s).unwrap().replace("\n", "\n< ").trim()
);
}
thread::sleep(Duration::from_millis(300));
}
serial.set_timeout(Duration::from_millis(3000)).unwrap();
let mut s = Vec::new();
let _ = serial.read_to_end(&mut s).is_ok();
if !s.is_empty() {
println!(
"< {}",
String::from_utf8(s).unwrap().replace("\n", "\n< ").trim()
);
}
}
serial.set_timeout(Duration::from_millis(10000)).unwrap();
return Connection::new_serial(serial);
}
Connection::new_tcp(TcpStream::connect((params.server_ip, params.server_port)).unwrap())
}
pub fn client(params: ClientParams) {
let mut buf1 = [0u8; 1];
let mut buf4 = [0u8; 4];
let mut buf8 = [0u8; 8];
let mut buf16 = [0u8; 16];
let mut buf = [0; 1024];
let mut tcp = TcpStream::connect((ip, port)).unwrap();
let mut tcp = connect(&params);
println!("Syncing...");
tcp.write_all(&[b'R', b'P', b'F', 30]).unwrap();
println!("Authenticating...");
tcp.write_all(&(key.len() as u32).to_be_bytes()).unwrap();
tcp.write_all(key.as_bytes()).unwrap();
tcp.write_all(&(params.key.len() as u32).to_be_bytes())
.unwrap();
tcp.write_all(params.key.as_bytes()).unwrap();
println!("Syncing...");
tcp.read_exact(&mut buf4).unwrap();
@ -77,7 +139,7 @@ pub fn client(ip: &str, port: u16, dest_ip: &str, dest_port: u16, key: &str, sle
.unwrap();
tcp.write(&i.to_be_bytes()).unwrap();
if let Some(x) = sockets.remove(&i) {
let _ = x.internal.shutdown(Shutdown::Both);
let _ = x.internal.close();
}
}
@ -87,7 +149,7 @@ pub fn client(ip: &str, port: u16, dest_ip: &str, dest_port: u16, key: &str, sle
.is_none()
{
if !did_anything {
thread::sleep(Duration::from_millis(sleep_delay_ms));
thread::sleep(Duration::from_millis(params.sleep_delay_ms));
}
continue;
}
@ -97,7 +159,9 @@ pub fn client(ip: &str, port: u16, dest_ip: &str, dest_port: u16, key: &str, sle
tcp.set_nonblocking(false);
match pt {
PacketType::NewClient => {
let mut tcp = SocketAdapter::new(TcpStream::connect((dest_ip, dest_port)).unwrap());
let mut tcp = SocketAdapter::new(Connection::new_tcp(
TcpStream::connect((params.dest_ip, params.dest_port)).unwrap(),
));
tcp.set_nonblocking(true);
sockets.insert((id, id += 1).0, tcp);
}
@ -105,7 +169,7 @@ pub fn client(ip: &str, port: u16, dest_ip: &str, dest_port: u16, key: &str, sle
PacketType::CloseClient => {
tcp.internal.read_exact(&mut buf8).unwrap();
if let Some(x) = sockets.remove(&u64::from_be_bytes(buf8)) {
let _ = x.internal.shutdown(Shutdown::Both);
let _ = x.internal.close();
}
}

View file

@ -1,6 +1,7 @@
mod client;
mod packet;
mod server;
mod server_connection;
mod socket_adapter;
use std::io::{Error, ErrorKind};
@ -8,12 +9,14 @@ use std::io::{Error, ErrorKind};
pub use client::*;
pub(crate) use packet::*;
pub use server::*;
pub(crate) use server_connection::*;
pub(crate) use socket_adapter::*;
pub(crate) fn io_sync<T>(result: Result<T, Error>) -> Result<Option<T>, Error> {
match result {
Ok(x) => Ok(Some(x)),
Err(x) if x.kind() == ErrorKind::WouldBlock => Ok(None),
Err(x) if x.kind() == ErrorKind::TimedOut => Ok(None),
Err(x) => Err(x),
}
}

View file

@ -1,22 +1,25 @@
use std::env;
use revpfw3::{client, server};
use revpfw3::{client, server, ClientParams};
fn main() {
let args: Vec<_> = env::args().skip(1).collect();
if (6..=7).contains(&args.len()) && args[0] == "client" {
client(
&args[1],
args[2].parse().unwrap(),
&args[3],
args[4].parse().unwrap(),
&args[5],
if args.len() == 7 {
if (6..=10).contains(&args.len()) && args[0] == "client" {
client(ClientParams {
server_ip: &args[1],
server_port: args[2].parse().unwrap(),
dest_ip: &args[3],
dest_port: args[4].parse().unwrap(),
key: &args[5],
sleep_delay_ms: if args.len() == 7 {
args[6].parse().unwrap()
} else {
1
},
);
modem_port: args.get(7).map(|x| x.as_str()),
modem_baud: args.get(8).map(|x| x.parse().unwrap()),
modem_init: args.get(9).map(|x| x.as_str()),
});
}
if (3..=4).contains(&args.len()) && args[0] == "server" {
server(
@ -31,5 +34,5 @@ fn main() {
}
eprintln!("Usage: \n\
\x20 revpfw3 server <port> <key> [<poll delay>]\n\
\x20 revpfw3 client <server ip> <server port> <destination ip> <destination port> <key> [<poll delay>]");
\x20 revpfw3 client <server ip> <server port> <destination ip> <destination port> <key> [<poll delay> [<modem port> <modem baud> <modem init>]]");
}

View file

@ -8,7 +8,7 @@ use std::{
vec,
};
use crate::{io_sync, PacketType, SocketAdapter};
use crate::{io_sync, Connection, PacketType, SocketAdapter};
pub fn server(port: u16, key: &str, sleep_delay_ms: u64) {
let mut buf1 = [0u8; 1];
@ -42,7 +42,7 @@ pub fn server(port: u16, key: &str, sleep_delay_ms: u64) {
tcpl.set_nonblocking(true).unwrap();
let mut tcp = SocketAdapter::new(tcp);
let mut tcp = SocketAdapter::new(Connection::new_tcp(tcp));
tcp.set_nonblocking(true);
let mut sockets: HashMap<u64, SocketAdapter> = HashMap::new();
let mut id = 0;
@ -51,7 +51,7 @@ pub fn server(port: u16, key: &str, sleep_delay_ms: u64) {
loop {
let mut did_anything = false;
if last_keep_alive_sent.elapsed().unwrap().as_secs() >= 20 {
if last_keep_alive_sent.elapsed().unwrap().as_secs() >= 10 {
last_keep_alive_sent = SystemTime::now();
tcp.write(&[PacketType::KeepAlive.ordinal() as u8]).unwrap();
}
@ -60,7 +60,7 @@ pub fn server(port: u16, key: &str, sleep_delay_ms: u64) {
}
if let Ok(new) = tcpl.accept() {
let mut new = SocketAdapter::new(new.0);
let mut new = SocketAdapter::new(Connection::new_tcp(new.0));
new.set_nonblocking(true);
sockets.insert((id, id += 1).0, new);
tcp.write(&[PacketType::NewClient.ordinal() as u8]).unwrap();
@ -99,7 +99,7 @@ pub fn server(port: u16, key: &str, sleep_delay_ms: u64) {
.unwrap();
tcp.write(&i.to_be_bytes()).unwrap();
if let Some(x) = sockets.remove(&i) {
let _ = x.internal.shutdown(Shutdown::Both);
let _ = x.internal.close();
}
}
@ -123,7 +123,7 @@ pub fn server(port: u16, key: &str, sleep_delay_ms: u64) {
PacketType::CloseClient => {
tcp.internal.read_exact(&mut buf8).unwrap();
if let Some(x) = sockets.remove(&u64::from_be_bytes(buf8)) {
let _ = x.internal.shutdown(Shutdown::Both);
let _ = x.internal.close();
}
}

139
src/server_connection.rs Normal file
View file

@ -0,0 +1,139 @@
use std::{
io::{self, ErrorKind, Read, Write},
net::{Shutdown, TcpStream},
ptr::NonNull,
time::Duration,
};
use serial::SerialPort;
trait ReadWrite: Write + Read + 'static {}
impl<T> ReadWrite for T where T: Write + Read + 'static {}
pub struct Connection {
readwrite: Box<dyn ReadWrite>,
data: NonNull<()>,
set_nonblocking_thunk: fn(NonNull<()>, bool) -> io::Result<()>,
close_thunk: fn(NonNull<()>) -> io::Result<()>,
is_nb: bool,
}
impl Write for Connection {
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.as_write().write_vectored(bufs)
}
fn write_all(&mut self, mut buf: &[u8]) -> io::Result<()> {
self.as_write().write_all(buf)
}
fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> {
self.as_write().write_fmt(fmt)
}
fn by_ref(&mut self) -> &mut Self
where
Self: Sized,
{
self
}
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.as_write().write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.as_write().flush()
}
}
impl Read for Connection {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.as_read().read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.as_read().read_vectored(bufs)
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.as_read().read_to_end(buf)
}
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
self.as_read().read_to_string(buf)
}
fn read_exact(&mut self, mut buf: &mut [u8]) -> io::Result<()> {
while !buf.is_empty() {
match self.read(buf) {
Ok(0) if self.is_nb => {
return Err(io::Error::new(ErrorKind::WouldBlock, "would block"))
}
Ok(0) => (),
Ok(n) => {
let tmp = buf;
buf = &mut tmp[n..];
}
Err(ref e) if e.kind() == ErrorKind::Interrupted => (),
Err(e) => return Err(e),
}
}
if !buf.is_empty() {
Err(io::Error::new(
ErrorKind::UnexpectedEof,
"failed to fill whole buffer",
))
} else {
Ok(())
}
}
}
impl Connection {
pub fn new_tcp(stream: TcpStream) -> Self {
let mut stream = Box::new(stream);
Connection {
data: NonNull::from(stream.as_mut()).cast(),
readwrite: stream,
set_nonblocking_thunk: |data, nb| unsafe {
data.cast::<TcpStream>().as_ref().set_nonblocking(nb)
},
close_thunk: |data| unsafe {
data.cast::<TcpStream>().as_ref().shutdown(Shutdown::Both)
},
is_nb: false,
}
}
pub fn new_serial<T: SerialPort + 'static>(serial: T) -> Self {
let mut serial = Box::new(serial);
Connection {
data: NonNull::from(serial.as_mut()).cast(),
readwrite: serial,
set_nonblocking_thunk: |data, nb| unsafe {
data.cast::<T>()
.as_mut()
.set_timeout(Duration::from_millis(if nb { 1 } else { 10000 }))
.map_err(|_| {
io::Error::new(io::ErrorKind::ConnectionAborted, "serial port went down")
})
},
// no need to close this.
close_thunk: |_data| Ok(()),
is_nb: false,
}
}
fn as_read(&mut self) -> &mut (dyn Read) {
&mut self.readwrite
}
fn as_write(&mut self) -> &mut (dyn Write) {
&mut self.readwrite
}
pub fn set_nonblocking(&mut self, nonblocking: bool) -> io::Result<()> {
self.is_nb = nonblocking;
(self.set_nonblocking_thunk)(self.data, nonblocking)
}
pub fn close(&self) -> io::Result<()> {
(self.close_thunk)(self.data)
}
}

View file

@ -5,7 +5,7 @@ use std::{
time::SystemTime,
};
use crate::io_sync;
use crate::{io_sync, Connection};
#[derive(Clone, Copy)]
enum Broken {
@ -23,7 +23,7 @@ impl From<Broken> for Error {
}
pub(crate) struct SocketAdapter {
pub(crate) internal: TcpStream,
pub(crate) internal: Connection,
written: usize,
to_write: usize,
write: [u8; 65536],
@ -34,9 +34,9 @@ pub(crate) struct SocketAdapter {
}
impl SocketAdapter {
pub fn new(tcp: TcpStream) -> SocketAdapter {
pub fn new(connection: Connection) -> SocketAdapter {
Self {
internal: tcp,
internal: connection,
written: 0,
to_write: 0,
write: [0u8; 65536],