How can i create a TCP stream using Rust? - rust

this is my first question and i hope you can help me.
Im trying to start a TCP stream to send HTTP messages using the Pnet library. The problem is when i try to send SYN packets but i dont receive any answer and i dont know whats the problem. I thought i was creating broken packets but i copy a SYN packet from a "telnet" operation and i get the same result.
I've tried so many ways and i still cant find a solution. Can anyone help me please?
extern crate pnet;
extern crate std;
use core::panic;
use std::io::Error;
use pnet::packet::ipv4::*;
use pnet::packet::ip::IpNextHeaderProtocol;
use pnet::packet::ip::IpNextHeaderProtocols;
use pnet::packet::ipv4::MutableIpv4Packet;
use pnet::packet::*;
use std::net::Ipv4Addr;
use pnet::transport::TransportChannelType::*;
use pnet::transport::TransportProtocol::*;
use pnet::transport::{transport_channel, ipv4_packet_iter};
use pnet::packet::*;
use pnet::packet::tcp::*;
use pnet::packet::tcp::MutableTcpPacket;
use pnet::packet::tcp::TcpOptionNumber;
pub fn create_ipv4_packet<'a>(buffer_ip: &'a mut [u8],ipv4Pac : pnet::packet::ipv4::Ipv4) -> MutableIpv4Packet {
let mut ipv4_packet = MutableIpv4Packet::new(buffer_ip).unwrap();
let ipv4_aux = ipv4Pac;
ipv4_packet.populate(&ipv4_aux);
let mut num = 0;
let mut inmutable = ipv4_packet.to_immutable();
let checks = pnet::packet::ipv4::checksum(&inmutable);
num = checks;
ipv4_packet.set_checksum(checks);
return ipv4_packet;
}
pub fn sendSYN( sourceP : u16, destPort : u16 , ipPacket : MutableIpv4Packet){
//TCP SYN Packet, obtain with telnet
let mut tmp: [u8; 40] = [234, 28,0,80,84, 233,15,246,
0,0,0,0,160,2,250,240,33,122,0,0,2,4,5,180,4,2,8,10,247,
143,213,137,0,0,0,0,1,3,3,7];
let tcpPackAux = MutableTcpPacket::new( &mut tmp);
let mut tcpPackOpt = tcpPackAux.unwrap();
tcpPackOpt.set_source(sourceP);
tcpPackOpt.set_destination(destPort);
let packetTCP = tcpPackOpt.packet();
let paqueteVecTCP = packetTCP.to_vec();
let ipPacketCopy = ipPacket;
let ipv4_TCPPayload =
pnet::packet::ipv4::Ipv4{version: ipPacketCopy.get_version(),
header_length: ipPacketCopy.get_header_length(),
dscp: ipPacketCopy.get_dscp(),
ecn: ipPacketCopy.get_ecn(),
total_length: ipPacketCopy.get_total_length(),
identification: ipPacketCopy.get_identification(),
flags: ipPacketCopy.get_flags(),
fragment_offset: ipPacketCopy.get_fragment_offset(),
ttl: ipPacketCopy.get_ttl(),
next_level_protocol: ipPacketCopy.get_next_level_protocol(),
checksum: ipPacketCopy.get_checksum(),
source: ipPacketCopy.get_source(),
destination: ipPacketCopy.get_destination(),
options: ipPacketCopy.get_options(),
payload: paqueteVecTCP.clone(), //Payload TCP
};
let mut protocol = pnet::transport::TransportChannelType::Layer3(IpNextHeaderProtocols::Tcp);
let (mut px, mut rx) = match transport_channel(4096, protocol) { // TamaƱo de 4096 bytes
Ok((tx, rx)) => (tx, rx),
Err(e) => panic!(),
};
let mut int_slice = [0u8; 60]; //60 = TCP + IP
let mut new_packet = create_ipv4_packet(&mut int_slice, ipv4_TCPPayload );
let addr = ipPacketCopy.get_destination();
//We send the IP + TCP packet
let packetDelivery = match px.send_to(new_packet, std::net::IpAddr::V4(addr)) {
Ok(n) => {
n;
},
Err(e) => {String::from("The packet wasnt sent. An error was detected");},
};
}
pub fn main(){
let sourcePort : u16 = 12345;
let destPort : u16 = 80;
let sourceAddress = Ipv4Addr::new(192,168,1,166);
let destAddress = Ipv4Addr::new(142,251,46,227);
let veectt = Vec::new();
let vectHexaPay = Vec::new();
let ipPac = pnet::packet::ipv4::Ipv4{version: 4,
header_length: 5,
dscp: 0,
ecn: 1,
total_length: 60,
identification: 15,
flags: 2,
fragment_offset: 0,
ttl: 64,
next_level_protocol: IpNextHeaderProtocol::new(6),
checksum: 0,
source: sourceAddress,
destination: destAddress,
options: veectt.clone(),
payload: vectHexaPay.clone(), //Payload TCP
};
let mut packetIP =[0u8; 60];
let mut mutableIpv4Pac = MutableIpv4Packet::new(&mut packetIP).unwrap();
mutableIpv4Pac.populate(&ipPac);
sendSYN(sourcePort, destPort, mutableIpv4Pac);
}

Related

Transferring memory between processes

I want to transfer an item between processes (specifically a TcpStream). I attempted to do this with a more complex example however failed in this. So I am trying to do this with a simpler example:
My current attempt is:
use bytes::{Buf, BytesMut};
use tokio::{
io::AsyncWriteExt,
net::{tcp::OwnedWriteHalf, TcpListener, TcpStream},
};
use tokio_stream::StreamExt;
use tokio_util::codec::{Decoder, FramedRead};
const TRANSFER_ADDRESS: &str = "127.0.0.1:8081";
#[tokio::main]
async fn main() {
if let Ok(existing_server_process_listener) =
TcpStream::connect(TRANSFER_ADDRESS).await
{
let (read, _write) = existing_server_process_listener.into_split();
let mut reader = FramedRead::new(read, DatabaseTransferDecoder);
let bytes = reader.next().await.unwrap().unwrap();
dbg!(&bytes);
let addr = usize::from_ne_bytes(bytes.try_into().unwrap());
dbg!(addr);
let ptr = addr as *mut u32;
dbg!(ptr);
let box_ptr = unsafe { Box::from_raw(ptr)};
dbg!(box_ptr);
}
else {
let update_listener = TcpListener::bind(TRANSFER_ADDRESS).await.unwrap();
let (stream, _socket) = update_listener.accept().await.unwrap();
// Splits our stream into read/write
let (_read, mut write) = stream.into_split();
let x = Box::new(4u32);
let ptr = Box::into_raw(x);
dbg!(ptr);
let addr = ptr as usize;
dbg!(addr);
let bytes = addr.to_ne_bytes();
dbg!(bytes);
write_fn(&mut write,&bytes).await;
}
}
async fn write_fn(writer: &mut OwnedWriteHalf, string: &[u8]) {
let buffer = {
let mut b = Vec::with_capacity(4 + string.len());
b.extend_from_slice(&u32::to_le_bytes(u32::try_from(string.len()).unwrap()));
b.extend_from_slice(string);
b
};
writer.write_all(&buffer).await.unwrap();
}
struct DatabaseTransferDecoder;
/// Implement `tokio_util::codec::decoder` for framed reads.
impl Decoder for DatabaseTransferDecoder {
type Error = std::io::Error;
type Item = Vec<u8>;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
// We use u32 for len marker, so need an initial 4 bytes
if src.len() < 4 {
return Ok(None);
}
// Get length
let length = {
let mut length_bytes = [0; 4];
length_bytes.copy_from_slice(&src[..4]);
u32::from_le_bytes(length_bytes) as usize
};
if src.len() < 4 + length {
src.reserve(4 + length - src.len());
return Ok(None);
}
// Read data
let data = src[4..4 + length].to_vec();
// Advance buffer to discard data
src.advance(4 + length);
Ok(Some(data))
}
}
Running the first process then running the second process causes the first process to output:
[src\main.rs:33] ptr = 0x000001f8b8435980
[src\main.rs:35] addr = 2167754938752
[src\main.rs:37] bytes = [
128,
89,
67,
184,
248,
1,
0,
0,
]
and the second process to output:
[src\main.rs:18] &bytes = [
128,
89,
67,
184,
248,
1,
0,
0,
]
[src\main.rs:20] addr = 2167754938752
[src\main.rs:22] ptr = 0x000001f8b8435980
[src\main.rs:24] box_ptr = error: process didn't exit successfully: `target\debug\testing-bin.exe` (exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)
Why would accessing this memory cause this error?

How to stop my tokio thread from blocking

I am writing a client for a Unix Domain Socket, which should listen for messages from a server, I got it to work after hours of researching (it shows 1-2 messages), but after that tokio crashes with the error: Error: Kind(WouldBlock), here is my code:
use std::env::{var, VarError};
use std::io::{self, Write};
use tokio::net::UnixStream;
#[tokio::main]
async fn main() -> io::Result<()> {
let hypr_instance_sig = match var("HYPRLAND_INSTANCE_SIGNATURE") {
Ok(var) => var,
Err(VarError::NotPresent) => panic!("Is hyprland running?"),
Err(VarError::NotUnicode(_)) => panic!("wtf no unicode?"),
};
let socket_path = format!("/tmp/hypr/{hypr_instance_sig}/.socket2.sock");
let stream = UnixStream::connect(socket_path).await?;
loop {
stream.readable().await?;
let mut buf = [0; 4096];
stream.try_read(&mut buf)?;
io::stdout().lock().write_all(&buf)?;
}
}
Could someone please help me?
I fully agree with #Caesar's comment.
don't use try_read, use read instead
slice the buffer to the correct size after reading
check for 0 bytes read, which indicates that the end of the stream was reached
use std::env::{var, VarError};
use std::io::{self, Write};
use tokio::io::AsyncReadExt;
use tokio::net::UnixStream;
#[tokio::main]
async fn main() -> io::Result<()> {
let hypr_instance_sig = match var("HYPRLAND_INSTANCE_SIGNATURE") {
Ok(var) => var,
Err(VarError::NotPresent) => panic!("Is hyprland running?"),
Err(VarError::NotUnicode(_)) => panic!("wtf no unicode?"),
};
let socket_path = format!("/tmp/hypr/{hypr_instance_sig}/.socket2.sock");
let mut stream = UnixStream::connect(socket_path).await?;
let mut buf = [0; 4096];
loop {
let num_read = stream.read(&mut buf).await?;
if num_read == 0 {
break;
}
let buf = &buf[..num_read];
io::stdout().lock().write_all(buf)?;
}
Ok(())
}
Disclaimer: I didn't test the code because I don't have the required socket file. It compiles, though.

Reading serial data using interrupt

I am trying to read a series of bytes from the serial pin, the interrupt is being called but I only read the first byte of the data each time.
I am using the library stm32f1xx-hal.
The idea is to store the data I receive in a buffer to use it whenever I need it later on the program. I got inspired by the example in the library.
Here is my code :
const BUFFER_LEN: usize = 20;
static mut BUFFER: &mut [u8; BUFFER_LEN] = &mut [0; BUFFER_LEN];
static mut WIDX: usize = 0;
static mut RX: Option<Rx<USART1>> = None;
static mut RX_PIN : MaybeUninit<stm32f1xx_hal::gpio::gpioa::PA10<Input<Floating>>> = MaybeUninit::uninit();
#[interrupt]
unsafe fn USART1() {
INT_COUNTER += 1;
cortex_m::interrupt::free(|_| {
if let Some(rx) = RX.as_mut() {
while rx.is_rx_not_empty() {
if let Ok(w) = nb::block!(rx.read()) {
BUFFER[WIDX] = w;
WIDX += 1;
if WIDX >= BUFFER_LEN - 1 {
WIDX = 0;
}
}
rx.listen_idle();
}
if rx.is_idle() {
rx.unlisten_idle();
WIDX = 0;
}
}
})
}
#[entry]
fn main() -> ! {
let mut dp: Peripherals = pac::Peripherals::take().unwrap();
let cp = cortex_m::Peripherals::take().unwrap();
let mut rcc: Rcc = dp.RCC.constrain();
let mut gpioc = dp.GPIOC.split();
let mut flash = dp.FLASH.constrain();
let mut gpioa = dp.GPIOA.split();
let mut afio = dp.AFIO.constrain();
let clocks_serial = rcc.cfgr.freeze(&mut flash.acr);
// USART1 on Pins A9 and A10
let pin_tx = gpioa.pa9.into_alternate_push_pull(&mut gpioa.crh);
let mut pin_rx = gpioa.pa10;
unsafe {
pac::NVIC::unmask(pac::Interrupt::USART1);
}
let serial = Serial::usart1(
dp.USART1,
(pin_tx, pin_rx),
&mut afio.mapr,
Config::default().baudrate(115200.bps()), // baud rate defined in herkulex doc : 115200
clocks_serial.clone(),
// &mut rcc.apb2,
);
// separate into tx and rx channels
let (mut tx, mut rx) = serial.split();
rx.listen();
rx.listen_idle();
cortex_m::interrupt::free(|_| unsafe {
RX.replace(rx);
});
loop {
// It is my sender, I can confirm I receive the message on the logical analyzer.
let message = servo.stat();
send_message(message, &mut tx);
cortex_m::asm::wfi(); // important
unsafe {
hprintln!("{:?}", BUFFER);
}
}
}

Why does my socket read lock the write of the data?

I use tokio::net::TcpStream to connect a small TCP server, I write a few bytes and expect to read the response from the server.
When I do that with the nc command, it works perfectly
[denis#docker-1 ~]$ echo "get" | nc 10.0.0.11 9090
[37e64dd7-91db-4c13-9f89-f1c87467ffb3][processed]
and the server logs show
Incoming peer instructions.
Waiting for peer instructions...
Reading bytes...
Got a few bytes [4]
Got a few bytes [[103, 101, 116, 10, 0, ...]]
Reading bytes...
Got a few bytes [0]
Got a few bytes [[0, 0, 0, 0, 0, 0,...]]
Writing some data back from peer : [37e64dd7-91db-4c13-9f89-f1c87467ffb3]
But from my Rust client, I can write the bytes but as soon as I want to read the data from the server, everything is locked (even the write action)
use std::collections::HashMap;
use std::ops::DerefMut;
use tokio::io;
use tokio::net::{TcpListener, TcpStream};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use uuid::Uuid;
use std::sync::RwLock;
use lazy_static::*;
#[tokio::main]
async fn main() {
let data = "set".to_string();
let mut stream = TcpStream::connect("10.0.0.11:9090").await.unwrap();
let ( mut read, mut write) = tokio::io::split(stream);
let u2 = data.as_bytes();
write.write_all(u2).await.unwrap();
let mut msg : [u8;1024] = [0;1024];
let _response_size = read.read(&mut msg).await.unwrap();
println!("GOT = {:?}", msg);
}
When looking at the server logs (see below), it reads the 3 bytes sent by the client, but then it is not able to read further, waiting to detect there is 0 byte left to read.
Incoming peer instructions.
Waiting for peer instructions...
Reading bytes...
Got a few bytes [3]
Got a few bytes [[115, 101, 116, 0, 0, ...]]
Reading bytes...
Here is the server code
use std::collections::HashMap;
use std::ops::DerefMut;
use tokio::io;
use tokio::net::{TcpListener, TcpStream};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use uuid::Uuid;
use std::sync::RwLock;
use lazy_static::*;
struct DataPool {
data : [u8;1024],
size : usize,
}
async fn whirl_socket( socket : &mut TcpStream ) -> Vec<DataPool> {
let mut pool: Vec<DataPool> = vec![];
let mut buf = [0; 1024];
// In a loop, read data from the socket until finished
loop {
println!("Reading bytes...");
buf = [0; 1024];
let n = match socket.read(&mut buf).await {
Ok(n) => n,
Err(e) => {
eprintln!("failed to read from socket; err = {:?}", e);
break;
}
};
println!("Got a few bytes [{}]", n);
println!("Got a few bytes [{:?}]", &buf);
pool.push(DataPool {
data: buf,
size: n,
});
if n == 0 {
break;
}
}
pool
}
async fn launch_server_listener() -> io::Result<()> {
println!("Listen to 9090...");
let listener = TcpListener::bind("10.0.0.11:9090").await?;
loop {
println!("Waiting for peer instructions...");
let (mut socket, _) = listener.accept().await?;
println!("Incoming peer instructions.");
tokio::spawn(async move {
let mut pool= whirl_socket(&mut socket).await;
let my_uuid = Uuid::new_v4();
// Write the data back
println!("Writing some data back from peer : [{}]", my_uuid);
let s = format!( "[{}][processed]\n", my_uuid.to_string());
let u = s.as_bytes();
if let Err(e) = socket.write_all(u).await {
eprintln!("failed to write to socket; err = {:?}", e);
return;
}
});
}
}
async fn start_servers() -> Result<(), Box<dyn std::error::Error>> {
let _r = tokio::join!(launch_server_listener());
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
start_servers().await?;
Ok(())
}
A read of 0 bytes means the read stream has closed. So in your client code you need to close the write stream. You can do this with .shutdown() from the AsyncWriteExt trait:
write.write_all(u2).await.unwrap();
write.shutdown().await.unwrap();

Future created by async block is not `Send` because of *mut u8 [duplicate]

This question already has an answer here:
How to send a pointer to another thread?
(1 answer)
Closed 5 months ago.
I was able to proceed forward to implement my asynchronous udp server. However I have this error showing up twice because my variable data has type *mut u8 which is not Send:
error: future cannot be sent between threads safely
help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `*mut u8`
note: captured value is not `Send`
And the code (MRE):
use std::error::Error;
use std::time::Duration;
use std::env;
use tokio::net::UdpSocket;
use tokio::{sync::mpsc, task, time}; // 1.4.0
use std::alloc::{alloc, Layout};
use std::mem;
use std::mem::MaybeUninit;
use std::net::SocketAddr;
const UDP_HEADER: usize = 8;
const IP_HEADER: usize = 20;
const AG_HEADER: usize = 4;
const MAX_DATA_LENGTH: usize = (64 * 1024 - 1) - UDP_HEADER - IP_HEADER;
const MAX_CHUNK_SIZE: usize = MAX_DATA_LENGTH - AG_HEADER;
const MAX_DATAGRAM_SIZE: usize = 0x10000;
/// A wrapper for [ptr::copy_nonoverlapping] with different argument order (same as original memcpy)
unsafe fn memcpy(dst_ptr: *mut u8, src_ptr: *const u8, len: usize) {
std::ptr::copy_nonoverlapping(src_ptr, dst_ptr, len);
}
// Different from https://doc.rust-lang.org/std/primitive.u32.html#method.next_power_of_two
// Returns the [exponent] from the smallest power of two greater than or equal to n.
const fn next_power_of_two_exponent(n: u32) -> u32 {
return 32 - (n - 1).leading_zeros();
}
async fn run_server(socket: UdpSocket) {
let mut missing_indexes: Vec<u16> = Vec::new();
let mut peer_addr = MaybeUninit::<SocketAddr>::uninit();
let mut data = std::ptr::null_mut(); // ptr for the file bytes
let mut len: usize = 0; // total len of bytes that will be written
let mut layout = MaybeUninit::<Layout>::uninit();
let mut buf = [0u8; MAX_DATA_LENGTH];
let mut start = false;
let (debounce_tx, mut debounce_rx) = mpsc::channel::<(usize, SocketAddr)>(3300);
let (network_tx, mut network_rx) = mpsc::channel::<(usize, SocketAddr)>(3300);
loop {
// Listen for events
let debouncer = task::spawn(async move {
let duration = Duration::from_millis(3300);
loop {
match time::timeout(duration, debounce_rx.recv()).await {
Ok(Some((size, peer))) => {
eprintln!("Network activity");
}
Ok(None) => {
if start == true {
eprintln!("Debounce finished");
break;
}
}
Err(_) => {
eprintln!("{:?} since network activity", duration);
}
}
}
});
// Listen for network activity
let server = task::spawn({
// async{
let debounce_tx = debounce_tx.clone();
async move {
while let Some((size, peer)) = network_rx.recv().await {
// Received a new packet
debounce_tx.send((size, peer)).await.expect("Unable to talk to debounce");
eprintln!("Received a packet {} from: {}", size, peer);
let packet_index: u16 = (buf[0] as u16) << 8 | buf[1] as u16;
if start == false { // first bytes of a new file: initialization // TODO: ADD A MUTEX to prevent many initializations
start = true;
let chunks_cnt: u32 = (buf[2] as u32) << 8 | buf[3] as u32;
let n: usize = MAX_DATAGRAM_SIZE << next_power_of_two_exponent(chunks_cnt);
unsafe {
layout.as_mut_ptr().write(Layout::from_size_align_unchecked(n, mem::align_of::<u8>()));
// /!\ data has type `*mut u8` which is not `Send`
data = alloc(layout.assume_init());
peer_addr.as_mut_ptr().write(peer);
}
let a: Vec<u16> = vec![0; chunks_cnt as usize]; //(0..chunks_cnt).map(|x| x as u16).collect(); // create a sorted vector with all the required indexes
missing_indexes = a;
}
missing_indexes[packet_index as usize] = 1;
unsafe {
let dst_ptr = data.offset((packet_index as usize * MAX_CHUNK_SIZE) as isize);
memcpy(dst_ptr, &buf[AG_HEADER], size - AG_HEADER);
};
println!("receiving packet {} from: {}", packet_index, peer);
}
}
});
// Prevent deadlocks
drop(debounce_tx);
match socket.recv_from(&mut buf).await {
Ok((size, src)) => {
network_tx.send((size, src)).await.expect("Unable to talk to network");
}
Err(e) => {
eprintln!("couldn't recieve a datagram: {}", e);
}
}
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let addr = env::args().nth(1).unwrap_or_else(|| "127.0.0.1:8080".to_string());
let socket = UdpSocket::bind(&addr).await?;
println!("Listening on: {}", socket.local_addr()?);
run_server(socket);
Ok(())
}
Since I was converting from synchronous to asynchronous code I know that, potentially, multiple thread would be writing to data, and that is probably why I encounter such error. But I don't know which syntax I could use to "clone" the mut ptr and make it unique for each thread (and same for the buffer).
As suggested by user4815162342 I think the best would be
to make pointer Send by wrapping it in a struct and declaring unsafe impl Send for NewStruct {}.
Any help strongly appreciated!
PS: Full code can be found on my github repository
Short version
Thanks to the comment of user4815162342 I decided to add an implementation for the mut ptr to be able to use it with Send and Sync, which allowed me to solve this part (there are still other issues, but beyond the scope of this question):
pub struct FileBuffer {
data: *mut u8
}
unsafe impl Send for FileBuffer {}
unsafe impl Sync for FileBuffer {}
//let mut data = std::ptr::null_mut(); // ptr for the file bytes
let mut fileBuffer: FileBuffer = FileBuffer { data: std::ptr::null_mut() };
Long version
use std::error::Error;
use std::time::Duration;
use std::env;
use tokio::net::UdpSocket;
use tokio::{sync::mpsc, task, time}; // 1.4.0
use std::alloc::{alloc, Layout};
use std::mem;
use std::mem::MaybeUninit;
use std::net::SocketAddr;
const UDP_HEADER: usize = 8;
const IP_HEADER: usize = 20;
const AG_HEADER: usize = 4;
const MAX_DATA_LENGTH: usize = (64 * 1024 - 1) - UDP_HEADER - IP_HEADER;
const MAX_CHUNK_SIZE: usize = MAX_DATA_LENGTH - AG_HEADER;
const MAX_DATAGRAM_SIZE: usize = 0x10000;
/// A wrapper for [ptr::copy_nonoverlapping] with different argument order (same as original memcpy)
unsafe fn memcpy(dst_ptr: *mut u8, src_ptr: *const u8, len: usize) {
std::ptr::copy_nonoverlapping(src_ptr, dst_ptr, len);
}
// Different from https://doc.rust-lang.org/std/primitive.u32.html#method.next_power_of_two
// Returns the [exponent] from the smallest power of two greater than or equal to n.
const fn next_power_of_two_exponent(n: u32) -> u32 {
return 32 - (n - 1).leading_zeros();
}
pub struct FileBuffer {
data: *mut u8
}
unsafe impl Send for FileBuffer {}
unsafe impl Sync for FileBuffer {}
async fn run_server(socket: UdpSocket) {
let mut missing_indexes: Vec<u16> = Vec::new();
let mut peer_addr = MaybeUninit::<SocketAddr>::uninit();
//let mut data = std::ptr::null_mut(); // ptr for the file bytes
let mut fileBuffer: FileBuffer = FileBuffer { data: std::ptr::null_mut() };
let mut len: usize = 0; // total len of bytes that will be written
let mut layout = MaybeUninit::<Layout>::uninit();
let mut buf = [0u8; MAX_DATA_LENGTH];
let mut start = false;
let (debounce_tx, mut debounce_rx) = mpsc::channel::<(usize, SocketAddr)>(3300);
let (network_tx, mut network_rx) = mpsc::channel::<(usize, SocketAddr)>(3300);
loop {
// Listen for events
let debouncer = task::spawn(async move {
let duration = Duration::from_millis(3300);
loop {
match time::timeout(duration, debounce_rx.recv()).await {
Ok(Some((size, peer))) => {
eprintln!("Network activity");
}
Ok(None) => {
if start == true {
eprintln!("Debounce finished");
break;
}
}
Err(_) => {
eprintln!("{:?} since network activity", duration);
}
}
}
});
// Listen for network activity
let server = task::spawn({
// async{
let debounce_tx = debounce_tx.clone();
async move {
while let Some((size, peer)) = network_rx.recv().await {
// Received a new packet
debounce_tx.send((size, peer)).await.expect("Unable to talk to debounce");
eprintln!("Received a packet {} from: {}", size, peer);
let packet_index: u16 = (buf[0] as u16) << 8 | buf[1] as u16;
if start == false { // first bytes of a new file: initialization // TODO: ADD A MUTEX to prevent many initializations
start = true;
let chunks_cnt: u32 = (buf[2] as u32) << 8 | buf[3] as u32;
let n: usize = MAX_DATAGRAM_SIZE << next_power_of_two_exponent(chunks_cnt);
unsafe {
layout.as_mut_ptr().write(Layout::from_size_align_unchecked(n, mem::align_of::<u8>()));
// /!\ data has type `*mut u8` which is not `Send`
fileBuffer.data = alloc(layout.assume_init());
peer_addr.as_mut_ptr().write(peer);
}
let a: Vec<u16> = vec![0; chunks_cnt as usize]; //(0..chunks_cnt).map(|x| x as u16).collect(); // create a sorted vector with all the required indexes
missing_indexes = a;
}
missing_indexes[packet_index as usize] = 1;
unsafe {
let dst_ptr = fileBuffer.data.offset((packet_index as usize * MAX_CHUNK_SIZE) as isize);
memcpy(dst_ptr, &buf[AG_HEADER], size - AG_HEADER);
};
println!("receiving packet {} from: {}", packet_index, peer);
}
}
});
// Prevent deadlocks
drop(debounce_tx);
match socket.recv_from(&mut buf).await {
Ok((size, src)) => {
network_tx.send((size, src)).await.expect("Unable to talk to network");
}
Err(e) => {
eprintln!("couldn't recieve a datagram: {}", e);
}
}
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let addr = env::args().nth(1).unwrap_or_else(|| "127.0.0.1:8080".to_string());
let socket = UdpSocket::bind(&addr).await?;
println!("Listening on: {}", socket.local_addr()?);
run_server(socket);
Ok(())
}

Resources