Skip to content

Commit 0885d7e

Browse files
committed
feat(state format): correct {de-,}serialization of Friends
Spec was slightly wrong, new corrections make things finally work.
1 parent 77ab939 commit 0885d7e

File tree

7 files changed

+99
-24
lines changed

7 files changed

+99
-24
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ authors = ["Zetok Zalbavar <[email protected]>"]
77
[dependencies]
88
clippy = { version = "*", optional = true }
99
log = "0.3"
10+
num-traits = "0.1"
1011
sodiumoxide = "0.0.12"
1112
mio = { git = "https://github.com/carllerche/mio", rev = "bf5de4d51ee00f140c4fcbd73b4d53717a3ac9e3" }
1213

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Current [API docs](https://zetok.github.io/tox) are a subject to changes.
2727
| libsodium | >=1.0.0 |
2828

2929
## Building
30-
Fairly simple. You'll need [Rust] >= 1.11 and [libsodium].
30+
Fairly simple. You'll need [Rust] >= 1.12.1 and [libsodium].
3131

3232
When you'll have deps, build debug version with
3333
```bash

src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ fn main() {
7979
let mut buf = [0; MAX_UDP_PACKET_SIZE];
8080
8181
// and wait for the answer
82-
let (mut bytes, mut sender);
82+
let (bytes, sender);
8383
loop {
8484
match socket.recv_from(&mut buf) {
8585
Ok(Some((b, s))) => {
@@ -128,6 +128,8 @@ fn main() {
128128
#[macro_use]
129129
extern crate log;
130130
extern crate mio;
131+
// for Zero trait
132+
extern crate num_traits;
131133
extern crate sodiumoxide;
132134

133135

src/toxcore/binary_io.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
//! Functions for binary IO.
2121
22+
use num_traits::identities::Zero;
2223

2324
/// Serialization into bytes.
2425
pub trait ToBytes {
@@ -131,6 +132,14 @@ pub trait FromBytes: Sized {
131132
}
132133

133134

135+
/// Append `0`s to given bytes up to `len`. Panics if `len` is smaller than
136+
/// padded `Vec`.
137+
pub fn append_zeros<T: Clone + Zero>(v: &mut Vec<T>, len: usize) {
138+
let l = v.len();
139+
v.append(&mut vec![T::zero(); len - l]);
140+
}
141+
142+
134143
// TODO: refactor ↓ using macros?
135144

136145
/// Safely cast `[u8; 2]` to `u16` using shift+or.

src/toxcore/state_format/old.rs

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -647,13 +647,15 @@ pub struct FriendState {
647647
pub const FRIENDSTATEBYTES: usize = 1 // "Status"
648648
+ PUBLICKEYBYTES
649649
/* Friend request message */ + REQUEST_MSG_LEN
650+
/* padding1 */ + 1
650651
/* actual size of FR message */ + 2
651652
/* Name; */ + NAME_LEN
652653
/* actual size of Name */ + 2
653654
/* Status msg; */ + STATUS_MSG_LEN
655+
/* padding2 */ + 1
654656
/* actual size of status msg */ + 2
655657
/* UserStatus */ + 1
656-
/* padding */ + 3
658+
/* padding3 */ + 3
657659
/* only used for sending FR */ + NOSPAMBYTES
658660
/* last time seen */ + 8;
659661

@@ -667,27 +669,32 @@ impl FromBytes for FriendState {
667669

668670
let Parsed(pk, bytes) = try!(PublicKey::parse_bytes(bytes));
669671

670-
// supply length
672+
// supply length and number of bytes that need to be padded
673+
// if no padding needed, supply `0`
671674
// TODO: refactor?
672-
fn get_bytes(bytes: &[u8], len: usize) -> ParseResult<Vec<u8>> {
675+
fn get_bytes(bytes: &[u8], len: usize, pad: usize)
676+
-> ParseResult<Vec<u8>>
677+
{
673678
let str_len = u16::from_be(array_to_u16(
674-
&[bytes[len], bytes[len+1]])) as usize;
679+
&[bytes[len+pad], bytes[len+pad+1]])) as usize;
675680
if str_len > len {
676681
return parse_error!("Value demands {} bytes when it is \
677682
supposed to take {}!", str_len, len)
678683
}
679684

680-
Ok(Parsed(bytes[..str_len].to_vec(), &bytes[len+2..]))
685+
Ok(Parsed(bytes[..str_len].to_vec(), &bytes[len+pad+2..]))
681686
};
682687

683-
let Parsed(fr_msg, bytes) = try!(get_bytes(bytes, REQUEST_MSG_LEN));
688+
let Parsed(fr_msg, bytes) = try!(get_bytes(bytes, REQUEST_MSG_LEN, 1));
684689

685690
// TODO: refactor?
686-
let Parsed(name_bytes, bytes) = try!(get_bytes(bytes, NAME_LEN));
691+
let Parsed(name_bytes, bytes) = try!(get_bytes(bytes, NAME_LEN, 0));
687692
let name = Name(name_bytes);
688693

689694
// TODO: refactor?
690-
let Parsed(status_msg_bytes, bytes) = try!(get_bytes(bytes, STATUS_MSG_LEN));
695+
let Parsed(status_msg_bytes, bytes) = try!(
696+
get_bytes(bytes, STATUS_MSG_LEN, 1)
697+
);
691698
let status_msg = StatusMsg(status_msg_bytes);
692699

693700
let Parsed(user_status, bytes) = try!(UserStatus::parse_bytes(bytes));
@@ -717,13 +724,12 @@ impl FromBytes for FriendState {
717724

718725
impl ToBytes for FriendState {
719726
fn to_bytes(&self) -> Vec<u8> {
720-
// extend vec with all contents of slice and padd with `0`s up to `len`
727+
// extend vec with all contents of slice and pad with `0`s up to `len`
721728
// assume that Vec isn't too big for fr_msg
722729
fn ext_vec(vec: &mut Vec<u8>, slice: &[u8], len: usize) {
723-
vec.extend_from_slice(slice);
724-
for _ in 0..(len - slice.len()) {
725-
vec.push(0);
726-
}
730+
let mut to_add = slice.to_vec();
731+
append_zeros(&mut to_add, len);
732+
vec.append(&mut to_add);
727733
}
728734

729735
let len_to_u16be = |len| u16_to_array((len as u16).to_be());
@@ -736,25 +742,29 @@ impl ToBytes for FriendState {
736742
// pk
737743
result.extend_from_slice(&self.pk.0);
738744

739-
// friend request msg and its length
745+
// friend request msg..
740746
ext_vec(&mut result, &self.fr_msg, REQUEST_MSG_LEN);
747+
// padding
748+
result.push(0);
749+
// .. and its length
741750
result.extend_from_slice(&len_to_u16be(self.fr_msg.len()));
742751

743752
// name and its length
744753
ext_vec(&mut result, &self.name.0, NAME_LEN);
745754
result.extend_from_slice(&len_to_u16be(self.name.0.len()));
746755

747-
// status msg and its length
756+
// status msg ..
748757
ext_vec(&mut result, &self.status_msg.0, STATUS_MSG_LEN);
758+
// padding
759+
result.push(0);
760+
// .. and its length
749761
result.extend_from_slice(&len_to_u16be(self.status_msg.0.len()));
750762

751763
// UserStatus
752764
result.push(self.user_status as u8);
753765

754766
// padding
755-
for _ in 0..3 {
756-
result.push(0);
757-
}
767+
append_zeros(&mut result, FRIENDSTATEBYTES - 12);
758768

759769
// NoSpam
760770
result.extend_from_slice(&self.nospam.0);
@@ -1414,13 +1424,14 @@ fn friend_state_parse_bytes_test() {
14141424
let mut bytes = fs_bytes.clone();
14151425
// TODO: change to inclusive range (`...`) once gets stabilised
14161426
// rust #28237
1417-
for b in 5..u8::max_value() {
1427+
for b in 5.. {
14181428
bytes[0] = b;
14191429
assert_error(&bytes, &format!("Unknown FriendStatus: {}", b));
1430+
if b == u8::max_value() { break; }
14201431
}
14211432
}
14221433

1423-
const FR_MSG_LEN_POS: usize = 1 + PUBLICKEYBYTES + REQUEST_MSG_LEN;
1434+
const FR_MSG_LEN_POS: usize = 1 + PUBLICKEYBYTES + REQUEST_MSG_LEN + 1;
14241435
{ // friend request message lenght check
14251436
let mut bytes = fs_bytes.clone();
14261437
for i in (REQUEST_MSG_LEN+1)..2500 { // too slow with bigger ranges
@@ -1446,7 +1457,8 @@ fn friend_state_parse_bytes_test() {
14461457
}
14471458
}
14481459

1449-
const STATUS_MSG_LEN_POS: usize = NAME_LEN_POS + STATUS_MSG_LEN + 2;
1460+
// padding + bytes containing length
1461+
const STATUS_MSG_LEN_POS: usize = NAME_LEN_POS + STATUS_MSG_LEN + 3;
14501462
{ // friend name lenght check
14511463
let mut bytes = fs_bytes.clone();
14521464
for i in (STATUS_MSG_LEN+1)..2500 { // too slow with bigger ranges

src/toxcore_tests/binary_io_tests.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919

2020
//! Tests for `binary_io` module.
2121
22-
use super::quickcheck::quickcheck;
22+
use num_traits::identities::Zero;
23+
use super::quickcheck::{quickcheck, TestResult};
2324

2425
use toxcore::binary_io::*;
2526

@@ -36,6 +37,49 @@ fn u64_to_array_and_back(num: u64) {
3637
assert_eq!(num, array_to_u64(&u64_to_array(num)));
3738
}
3839

40+
41+
// append_zeros()
42+
43+
macro_rules! test_append_zeros_for {
44+
($($num:ty, $tname_f:ident, $tname_p:ident),+) => ($(
45+
#[test]
46+
#[should_panic]
47+
fn $tname_f() {
48+
fn with_bytes(bytes: Vec<$num>, len: usize) -> TestResult {
49+
if bytes.len() > len {
50+
// this should nicely panic
51+
append_zeros(&mut bytes.clone(), len);
52+
}
53+
TestResult::discard()
54+
}
55+
quickcheck(with_bytes as fn(Vec<$num>, usize) -> TestResult);
56+
}
57+
58+
#[test]
59+
fn $tname_p() {
60+
fn with_bytes(bytes: Vec<$num>, len: usize) -> TestResult {
61+
if bytes.len() > len {
62+
return TestResult::discard()
63+
}
64+
65+
let mut bc = bytes.clone();
66+
append_zeros(&mut bc, len);
67+
assert_eq!(bytes[..], bc[..bytes.len()]);
68+
assert_eq!(&vec![Zero::zero(); len - bytes.len()] as &[$num],
69+
&bc[bytes.len()..]);
70+
TestResult::passed()
71+
}
72+
quickcheck(with_bytes as fn(Vec<$num>, usize) -> TestResult);
73+
}
74+
)+)
75+
}
76+
test_append_zeros_for!(
77+
u8, append_zeros_test_u8_fail, append_zeros_test_u8_pass,
78+
u16, append_zeros_test_u16_fail, append_zeros_test_u16_pass,
79+
u32, append_zeros_test_u32_fail, append_zeros_test_u32_pass,
80+
u64, append_zeros_test_u64_fail, append_zeros_test_u64_pass
81+
);
82+
3983
#[test]
4084
fn array_to_u16_test() {
4185
assert_eq!(array_to_u16(&[0, 0]), 0);

0 commit comments

Comments
 (0)