Reputation: 8943
First of all, this is the php script that I'm using to send UDP packets to my program for testing.
<?php
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
$pack = pack('C*', 4, 3, 1, 0);
socket_sendto($sock, $pack, strlen($pack), 0, '127.0.0.1', 1337);
socket_close($sock);
Super simple, pack some binary and send it over the wire to my program. Everything is a known unique value so we can ensure that information is being read into the correct location in the struct.
#![allow(non_snake_case)]
use std::net::UdpSocket;
use std::mem::size_of;
#[repr(C, packed)]
#[derive(Debug, Copy, Clone)]
struct ISP_TINY {
Size: u8, // Always 4
Type: u8, // Always ISP_TINY = 3
ReqI: u8, // 0 Unless return of a request for information.
SubT: u8, // Sub Type from the TINY_ enumeration.
}
fn main() -> std::io::Result<()>
{
// Some output so that we know the program has actally started.
println!("Running ...");
// Here we bind to the UDP socket, but the question mark allows us to return early if there is an error and end the program then and there.
let socket = UdpSocket::bind("0.0.0.0:1337")?;
// We'll read into this buffer space, but it has to be as big as or bigger than the largest packet your program can receive, otherwise it will cut off the rest of the data.
let mut buf = [0; 256];
loop
{
// recv_from blocks, and will wait (in sleep) until we get a packet to our bound socket.
let (bytes, socketAddress) = socket.recv_from(&mut buf)?;
// Once we get a packet, read from our buffer upto the packet length in bytes.
let packet = &mut buf[..bytes];
// Check that it's of the size we understand and want.
if bytes != size_of::<ISP_TINY>()
{
println!("Got packet of size {} need packet of size {}", bytes, size_of::<ISP_TINY>());
// Here we implicitly discard a packet we don't like and contiune the loop.
continue;
}
// When we get a packet we want, we print it's contents, it's size and where it came from.
println!("Packet Recv {:#?} of size {} from {}", packet, bytes, socketAddress);
}
}
I've gone though a tremendous numbers of implementations to make rust happy. Over the past 24 hours, I think I've done about 10 different designs. None of them seems to have made it happy with the solutions that I've come up with.
This doesn't look like it would be a hard problem. I have the data, I can just slice into it? Right?
let tiny = ISP_TINY {
Size: packet[0 .. 1],
Type: packet[1 .. 2],
ReqI: packet[2 .. 3],
SubT: packet[3 .. 4]
};
Wrong
error[E0308]: mismatched types
--> src/main.rs:42:19
|
42 | Size: packet[0 .. 1],
| ^^^^^^^^^^^^^^ expected `u8`, found slice `[u8]`
error[E0308]: mismatched types
--> src/main.rs:43:19
|
43 | Type: packet[1 .. 2],
| ^^^^^^^^^^^^^^ expected `u8`, found slice `[u8]`
error[E0308]: mismatched types
--> src/main.rs:44:19
|
44 | ReqI: packet[2 .. 3],
| ^^^^^^^^^^^^^^ expected `u8`, found slice `[u8]`
error[E0308]: mismatched types
--> src/main.rs:45:19
|
45 | SubT: packet[3 .. 4]
| ^^^^^^^^^^^^^^ expected `u8`, found slice `[u8]`
error: aborting due to 4 previous errors
So I said to myself, maybe I need to create an implementation ...
impl ISP_TINY
{
fn from(&self, packet: &[u8])
{
self.Size: packet[0 .. 1],
self.Type: packet[1 .. 2],
self.ReqI: packet[2 .. 3],
self.SubT: packet[3 .. 4]
}
}
It doesn't like that either.
error: expected one of `!`, `(`, `::`, `;`, `<`, or `}`, found `[`
--> src/main.rs:19:26
|
19 | self.Size: packet[0 .. 1],
| - ^ expected one of `!`, `(`, `::`, `;`, `<`, or `}`
| |
| tried to parse a type due to this
error: aborting due to previous error
These are the two of the 10 that I thought would be the sensible solutions. But they don't work and I'm not sure how to get around this problem within the Rust language. How do you read raw binary data from packets into structs!?
Upvotes: 3
Views: 3059
Reputation: 6867
Just index by an integer to get a single byte, e.g. packet[0]
instead of packet[0..1]
. This will give you an u8
instead of a slice of length 1.
For converting an array of bytes to a larger integer, e.g. u16
, i64
, etc., one can use functions like from_le_bytes, from_be_bytes
and from_ne_bytes
defined on the native integers.
Upvotes: 4