Media wire: the encoder refuses a record over the ceiling too

A producer that builds an oversized record without going through the FEC
policy would otherwise learn only when the receiver silently dropped it.
encode_media_wire_record now refuses anything over
GAMECULT_MEDIA_MAX_WIRE_BYTES, with the decoder's message. The decode ceiling
test pads a valid record by one byte to stand in for a peer that sent one.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-09-30 08:11:26 +02:00
commit 1bbc0ace69
2 changed files with 23 additions and 3 deletions

View file

@ -182,7 +182,14 @@ pub fn encode_media_wire_record(
},
};
encode_cultnet_message_to_vec(&message, CultNetWireContract::CultNetSchemaV0).map_err(Into::into)
let wire = encode_cultnet_message_to_vec(&message, CultNetWireContract::CultNetSchemaV0)?;
if wire.len() > GAMECULT_MEDIA_MAX_WIRE_BYTES {
return Err(anyhow!(
"media record is {} bytes, over the {GAMECULT_MEDIA_MAX_WIRE_BYTES}-byte ceiling",
wire.len()
));
}
Ok(wire)
}
/// Unwraps a media record from the wire.

View file

@ -512,8 +512,10 @@ fn a_media_record_one_byte_over_the_ceiling_is_refused_at_decode() {
decode_media_wire_record(&wire)
.unwrap_or_else(|error| panic!("{name} at the ceiling is refused: {error}"));
let over = encode_media_wire_record(&wrap(at + 1), provenance()).unwrap();
assert_eq!(over.len(), ceiling + 1);
// The encoder refuses to make an over-ceiling record, so one byte of
// padding stands in for a peer that sent one.
let mut over = wire.clone();
over.push(0);
let error = decode_media_wire_record(&over).unwrap_err();
assert!(error.to_string().contains("ceiling"), "{name}: {error}");
}
@ -639,3 +641,14 @@ fn a_session_refuses_to_reassemble_more_than_the_ceiling_on_the_media_channel()
let error = deliver(GAMECULT_MEDIA_CHANNEL).unwrap_err();
assert!(error.to_string().contains("max_payload_bytes"), "{error}");
}
/// A producer learns at encode time that a record is over the ceiling, rather
/// than the receiver dropping it.
#[test]
fn the_encoder_refuses_a_record_over_the_ceiling() {
let wrap = |payload: usize| GameCultMediaWireRecord::AudioParity(audio_parity(payload, 300));
let at = payload_for_wire_len(GAMECULT_MEDIA_MAX_WIRE_BYTES, &wrap);
assert!(encode_media_wire_record(&wrap(at), provenance()).is_ok());
let error = encode_media_wire_record(&wrap(at + 1), provenance()).unwrap_err();
assert!(error.to_string().contains("ceiling"), "{error}");
}